- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / language_switch_menu.cc
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/chromeos/login/language_switch_menu.h"
6
7 #include "ash/shell.h"
8 #include "base/i18n/rtl.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/threading/thread_restrictions.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/chromeos/input_method/input_method_util.h"
14 #include "chrome/browser/chromeos/login/language_list.h"
15 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
16 #include "chrome/common/pref_names.h"
17 #include "chromeos/ime/input_method_manager.h"
18 #include "grit/generated_resources.h"
19 #include "grit/platform_locale_settings.h"
20 #include "ui/aura/root_window.h"
21 #include "ui/base/l10n/l10n_util.h"
22 #include "ui/base/resource/resource_bundle.h"
23 #include "ui/gfx/platform_font_pango.h"
24 #include "ui/views/controls/button/menu_button.h"
25 #include "ui/views/controls/menu/menu_item_view.h"
26 #include "ui/views/controls/menu/menu_runner.h"
27 #include "ui/views/controls/menu/submenu_view.h"
28 #include "ui/views/widget/widget.h"
29
30 namespace {
31
32 const int kLanguageMainMenuSize = 5;
33 // TODO(glotov): need to specify the list as a part of the image customization.
34 const char kLanguagesTopped[] = "es,it,de,fr,en-US";
35 const int kMoreLanguagesSubMenu = 200;
36
37 // Notifies all views::Widgets attached to |window|'s hierarchy that their
38 // locale has changed.
39 void NotifyLocaleChanged(aura::Window* window) {
40   views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window);
41   if (widget)
42     widget->LocaleChanged();
43
44   const aura::Window::Windows& children = window->children();
45   for (aura::Window::Windows::const_iterator it = children.begin();
46        it != children.end(); ++it) {
47     NotifyLocaleChanged(*it);
48   }
49 }
50
51 }  // namespace
52
53 namespace chromeos {
54
55 LanguageSwitchMenu::LanguageSwitchMenu()
56     : menu_(new views::MenuItemView(this)),
57       menu_runner_(new views::MenuRunner(menu_)) {
58 }
59
60 LanguageSwitchMenu::~LanguageSwitchMenu() {}
61
62 void LanguageSwitchMenu::InitLanguageMenu() {
63   // Update LanguageList to contain entries in current locale.
64   language_list_.reset(new LanguageList);
65   language_list_->CopySpecifiedLanguagesUp(kLanguagesTopped);
66
67   // Clear older menu items.
68   if (menu_->HasSubmenu()) {
69     const int old_count = menu_->GetSubmenu()->child_count();
70     for (int i = 0; i < old_count; ++i)
71       menu_->RemoveMenuItemAt(0);
72   }
73
74   // Fill menu items with updated items.
75   for (int line = 0; line != kLanguageMainMenuSize; line++) {
76     menu_->AppendMenuItemWithLabel(line,
77                                    language_list_->GetLanguageNameAt(line));
78   }
79
80   menu_->AppendSeparator();
81   views::MenuItemView* submenu = menu_->AppendSubMenu(
82       kMoreLanguagesSubMenu,
83       l10n_util::GetStringUTF16(IDS_LANGUAGES_MORE));
84
85   for (int line = kLanguageMainMenuSize;
86        line != language_list_->languages_count(); ++line) {
87     submenu->AppendMenuItemWithLabel(line,
88                                      language_list_->GetLanguageNameAt(line));
89   }
90
91   menu_->ChildrenChanged();
92 }
93
94 string16 LanguageSwitchMenu::GetCurrentLocaleName() const {
95   DCHECK(g_browser_process);
96   const std::string locale = g_browser_process->GetApplicationLocale();
97   int index = language_list_->GetIndexFromLocale(locale);
98   CHECK_NE(-1, index) << "Unknown locale: " << locale;
99   return language_list_->GetLanguageNameAt(index);
100 };
101
102 void LanguageSwitchMenu::SetFirstLevelMenuWidth(int width) {
103   DCHECK(menu_ != NULL);
104
105   menu_->GetSubmenu()->set_minimum_preferred_width(width);
106 }
107
108 // static
109 bool LanguageSwitchMenu::SwitchLanguage(const std::string& locale) {
110   DCHECK(g_browser_process);
111   if (g_browser_process->GetApplicationLocale() == locale) {
112     return false;
113   }
114   // TODO(markusheintz): Change the if condition to prefs->IsUserModifiable()
115   // once Mattias landed his pending patch.
116   if (!g_browser_process->local_state()->
117       IsManagedPreference(prefs::kApplicationLocale)) {
118     std::string loaded_locale;
119     {
120       // Reloading resource bundle causes us to do blocking IO on UI thread.
121       // Temporarily allow it until we fix http://crosbug.com/11102
122       base::ThreadRestrictions::ScopedAllowIO allow_io;
123       // Switch the locale.
124       loaded_locale =
125           ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale);
126     }
127     CHECK(!loaded_locale.empty()) << "Locale could not be found for " << locale;
128
129     LoadFontsForCurrentLocale();
130
131     // The following line does not seem to affect locale anyhow. Maybe in
132     // future..
133     g_browser_process->SetApplicationLocale(locale);
134
135     PrefService* prefs = g_browser_process->local_state();
136     prefs->SetString(prefs::kApplicationLocale, locale);
137
138     return true;
139   }
140   return false;
141 }
142
143 // static
144 void LanguageSwitchMenu::LoadFontsForCurrentLocale() {
145   // Switch the font.
146   gfx::PlatformFontPango::ReloadDefaultFont();
147   ResourceBundle::GetSharedInstance().ReloadFonts();
148 }
149
150 // static
151 void LanguageSwitchMenu::SwitchLanguageAndEnableKeyboardLayouts(
152     const std::string& locale) {
153   if (SwitchLanguage(locale)) {
154     // If we have switched the locale, enable the keyboard layouts that
155     // are necessary for the new locale.  Change the current input method
156     // to the hardware keyboard layout since the input method currently in
157     // use may not be supported by the new locale (3rd parameter).
158     input_method::InputMethodManager* manager =
159         input_method::InputMethodManager::Get();
160     manager->EnableLayouts(
161         locale,
162         manager->GetInputMethodUtil()->GetHardwareInputMethodId());
163   }
164 }
165
166 ////////////////////////////////////////////////////////////////////////////////
167 // views::MenuButtonListener implementation.
168
169 void LanguageSwitchMenu::OnMenuButtonClicked(views::View* source,
170                                              const gfx::Point& point) {
171   DCHECK(menu_ != NULL);
172   views::MenuButton* button = static_cast<views::MenuButton*>(source);
173
174   // We align on the left edge of the button for non RTL case.
175   // MenuButton passes in |point| the lower left corner for RTL and the
176   // lower right corner for non-RTL (with menu_offset applied).
177   const int reverse_offset = button->width() + button->menu_offset().x() * 2;
178   gfx::Point new_pt(point);
179   if (base::i18n::IsRTL())
180     new_pt.set_x(point.x() + reverse_offset);
181   else
182     new_pt.set_x(point.x() - reverse_offset);
183
184   if (menu_runner_->RunMenuAt(button->GetWidget(), button,
185           gfx::Rect(new_pt, gfx::Size()), views::MenuItemView::TOPLEFT,
186           ui::MENU_SOURCE_NONE, views::MenuRunner::HAS_MNEMONICS) ==
187               views::MenuRunner::MENU_DELETED)
188     return;
189 }
190
191 ////////////////////////////////////////////////////////////////////////////////
192 // views::MenuDelegate implementation.
193
194 void LanguageSwitchMenu::ExecuteCommand(int command_id, int event_flags) {
195   const std::string locale = language_list_->GetLocaleFromIndex(command_id);
196   // Here, we should enable keyboard layouts associated with the locale so
197   // that users can use those keyboard layouts on the login screen.
198   SwitchLanguageAndEnableKeyboardLayouts(locale);
199   InitLanguageMenu();
200   NotifyLocaleChanged(ash::Shell::GetPrimaryRootWindow());
201 }
202
203 }  // namespace chromeos