| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/login/language_switch_menu.h" |
| |
| #include "ash/shell.h" |
| #include "base/i18n/rtl.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chromeos/input_method/input_method_util.h" |
| #include "chrome/browser/chromeos/login/language_list.h" |
| #include "chrome/browser/chromeos/login/screens/screen_observer.h" |
| #include "chrome/common/pref_names.h" |
| #include "chromeos/ime/input_method_manager.h" |
| #include "grit/generated_resources.h" |
| #include "grit/platform_locale_settings.h" |
| #include "ui/aura/root_window.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/gfx/platform_font_pango.h" |
| #include "ui/views/controls/button/menu_button.h" |
| #include "ui/views/controls/menu/menu_item_view.h" |
| #include "ui/views/controls/menu/menu_runner.h" |
| #include "ui/views/controls/menu/submenu_view.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace { |
| |
| const int kLanguageMainMenuSize = 5; |
| // TODO(glotov): need to specify the list as a part of the image customization. |
| const char kLanguagesTopped[] = "es,it,de,fr,en-US"; |
| const int kMoreLanguagesSubMenu = 200; |
| |
| // Notifies all views::Widgets attached to |window|'s hierarchy that their |
| // locale has changed. |
| void NotifyLocaleChanged(aura::Window* window) { |
| views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window); |
| if (widget) |
| widget->LocaleChanged(); |
| |
| const aura::Window::Windows& children = window->children(); |
| for (aura::Window::Windows::const_iterator it = children.begin(); |
| it != children.end(); ++it) { |
| NotifyLocaleChanged(*it); |
| } |
| } |
| |
| } // namespace |
| |
| namespace chromeos { |
| |
| LanguageSwitchMenu::LanguageSwitchMenu() |
| : menu_(new views::MenuItemView(this)), |
| menu_runner_(new views::MenuRunner(menu_)) { |
| } |
| |
| LanguageSwitchMenu::~LanguageSwitchMenu() {} |
| |
| void LanguageSwitchMenu::InitLanguageMenu() { |
| // Update LanguageList to contain entries in current locale. |
| language_list_.reset(new LanguageList); |
| language_list_->CopySpecifiedLanguagesUp(kLanguagesTopped); |
| |
| // Clear older menu items. |
| if (menu_->HasSubmenu()) { |
| const int old_count = menu_->GetSubmenu()->child_count(); |
| for (int i = 0; i < old_count; ++i) |
| menu_->RemoveMenuItemAt(0); |
| } |
| |
| // Fill menu items with updated items. |
| for (int line = 0; line != kLanguageMainMenuSize; line++) { |
| menu_->AppendMenuItemWithLabel(line, |
| language_list_->GetLanguageNameAt(line)); |
| } |
| |
| menu_->AppendSeparator(); |
| views::MenuItemView* submenu = menu_->AppendSubMenu( |
| kMoreLanguagesSubMenu, |
| l10n_util::GetStringUTF16(IDS_LANGUAGES_MORE)); |
| |
| for (int line = kLanguageMainMenuSize; |
| line != language_list_->languages_count(); ++line) { |
| submenu->AppendMenuItemWithLabel(line, |
| language_list_->GetLanguageNameAt(line)); |
| } |
| |
| menu_->ChildrenChanged(); |
| } |
| |
| string16 LanguageSwitchMenu::GetCurrentLocaleName() const { |
| DCHECK(g_browser_process); |
| const std::string locale = g_browser_process->GetApplicationLocale(); |
| int index = language_list_->GetIndexFromLocale(locale); |
| CHECK_NE(-1, index) << "Unknown locale: " << locale; |
| return language_list_->GetLanguageNameAt(index); |
| }; |
| |
| void LanguageSwitchMenu::SetFirstLevelMenuWidth(int width) { |
| DCHECK(menu_ != NULL); |
| |
| menu_->GetSubmenu()->set_minimum_preferred_width(width); |
| } |
| |
| // static |
| bool LanguageSwitchMenu::SwitchLanguage(const std::string& locale) { |
| DCHECK(g_browser_process); |
| if (g_browser_process->GetApplicationLocale() == locale) { |
| return false; |
| } |
| // TODO(markusheintz): Change the if condition to prefs->IsUserModifiable() |
| // once Mattias landed his pending patch. |
| if (!g_browser_process->local_state()-> |
| IsManagedPreference(prefs::kApplicationLocale)) { |
| std::string loaded_locale; |
| { |
| // Reloading resource bundle causes us to do blocking IO on UI thread. |
| // Temporarily allow it until we fix http://crosbug.com/11102 |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| // Switch the locale. |
| loaded_locale = |
| ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale); |
| } |
| CHECK(!loaded_locale.empty()) << "Locale could not be found for " << locale; |
| |
| LoadFontsForCurrentLocale(); |
| |
| // The following line does not seem to affect locale anyhow. Maybe in |
| // future.. |
| g_browser_process->SetApplicationLocale(locale); |
| |
| PrefService* prefs = g_browser_process->local_state(); |
| prefs->SetString(prefs::kApplicationLocale, locale); |
| |
| return true; |
| } |
| return false; |
| } |
| |
| // static |
| void LanguageSwitchMenu::LoadFontsForCurrentLocale() { |
| // Switch the font. |
| gfx::PlatformFontPango::ReloadDefaultFont(); |
| ResourceBundle::GetSharedInstance().ReloadFonts(); |
| } |
| |
| // static |
| void LanguageSwitchMenu::SwitchLanguageAndEnableKeyboardLayouts( |
| const std::string& locale) { |
| if (SwitchLanguage(locale)) { |
| // If we have switched the locale, enable the keyboard layouts that |
| // are necessary for the new locale. Change the current input method |
| // to the hardware keyboard layout since the input method currently in |
| // use may not be supported by the new locale (3rd parameter). |
| input_method::InputMethodManager* manager = |
| input_method::InputMethodManager::Get(); |
| manager->EnableLayouts( |
| locale, |
| manager->GetInputMethodUtil()->GetHardwareInputMethodId()); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // views::MenuButtonListener implementation. |
| |
| void LanguageSwitchMenu::OnMenuButtonClicked(views::View* source, |
| const gfx::Point& point) { |
| DCHECK(menu_ != NULL); |
| views::MenuButton* button = static_cast<views::MenuButton*>(source); |
| |
| // We align on the left edge of the button for non RTL case. |
| // MenuButton passes in |point| the lower left corner for RTL and the |
| // lower right corner for non-RTL (with menu_offset applied). |
| const int reverse_offset = button->width() + button->menu_offset().x() * 2; |
| gfx::Point new_pt(point); |
| if (base::i18n::IsRTL()) |
| new_pt.set_x(point.x() + reverse_offset); |
| else |
| new_pt.set_x(point.x() - reverse_offset); |
| |
| if (menu_runner_->RunMenuAt(button->GetWidget(), button, |
| gfx::Rect(new_pt, gfx::Size()), views::MenuItemView::TOPLEFT, |
| ui::MENU_SOURCE_NONE, views::MenuRunner::HAS_MNEMONICS) == |
| views::MenuRunner::MENU_DELETED) |
| return; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // views::MenuDelegate implementation. |
| |
| void LanguageSwitchMenu::ExecuteCommand(int command_id, int event_flags) { |
| const std::string locale = language_list_->GetLocaleFromIndex(command_id); |
| // Here, we should enable keyboard layouts associated with the locale so |
| // that users can use those keyboard layouts on the login screen. |
| SwitchLanguageAndEnableKeyboardLayouts(locale); |
| InitLanguageMenu(); |
| NotifyLocaleChanged(ash::Shell::GetPrimaryRootWindow()); |
| } |
| |
| } // namespace chromeos |