summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authoryusukes@chromium.org <yusukes@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-09 13:31:16 +0000
committeryusukes@chromium.org <yusukes@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-09 13:31:16 +0000
commit432867bf871d35ab5da94a0d24fd5af9f6dc7d79 (patch)
tree1a7d82fefd42e5782d1819fbfc46e6c6f1ac13db /chrome/browser
parentca4b5fa384e6ac932826d178f374d0d23e1296af (diff)
downloadchromium_src-432867bf871d35ab5da94a0d24fd5af9f6dc7d79.zip
chromium_src-432867bf871d35ab5da94a0d24fd5af9f6dc7d79.tar.gz
chromium_src-432867bf871d35ab5da94a0d24fd5af9f6dc7d79.tar.bz2
Split the LanguageMenuButton class into 2 classes so that OOBE screen could easily reuse the drop-down menu (but not the "US" button).
The change is necessary for issue 6185. - A new class InputMethodMenu, which provides the drop-down menu for switching input methods and keyboard layouts, is added. - The LanguageMenuButton class is modified. Most of the code is moved to the new InputMethodMenu class. Now the class only provides the status area button ("US"). The InputMethodMenu class is almost identical to the old LanguageMenuButton, but - The new one does not inherit StatusAreaButton since it's not a button - UpdateIndicator() is renamed to UpdateUI() and changed to pure virtual since the new class does not have UI other than the drop-down menu. - SetMinimumWidth() is added since the OOBE screen uses fix-width menu. I think it might be better to rename language_menu_button.h to input_method_menu_button.h as well. If it's necessary, I'll file a bug and do it in a separate CL. BUG=chromium-os:6185 TEST=manually checked, ran the unittests and browser tests as well. Review URL: http://codereview.chromium.org/3562008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62082 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/chromeos/cros/cros_mock.cc4
-rw-r--r--chrome/browser/chromeos/login/login_browsertest.cc2
-rw-r--r--chrome/browser/chromeos/status/input_method_menu.cc624
-rw-r--r--chrome/browser/chromeos/status/input_method_menu.h149
-rw-r--r--chrome/browser/chromeos/status/input_method_menu_unittest.cc (renamed from chrome/browser/chromeos/status/language_menu_button_unittest.cc)56
-rw-r--r--chrome/browser/chromeos/status/language_menu_button.cc596
-rw-r--r--chrome/browser/chromeos/status/language_menu_button.h116
7 files changed, 830 insertions, 717 deletions
diff --git a/chrome/browser/chromeos/cros/cros_mock.cc b/chrome/browser/chromeos/cros/cros_mock.cc
index 168bf03..2e54bca 100644
--- a/chrome/browser/chromeos/cros/cros_mock.cc
+++ b/chrome/browser/chromeos/cros/cros_mock.cc
@@ -249,8 +249,8 @@ void CrosMock::SetInputMethodLibraryStatusAreaExpectations() {
.WillRepeatedly(InvokeWithoutArgs(CreateFallbackInputMethodDescriptors))
.RetiresOnSaturation();
EXPECT_CALL(*mock_input_method_library_, current_ime_properties())
- .Times(1)
- .WillOnce((ReturnRef(ime_properties_)))
+ .Times(AnyNumber())
+ .WillRepeatedly((ReturnRef(ime_properties_)))
.RetiresOnSaturation();
EXPECT_CALL(*mock_input_method_library_, SetImeConfig(_, _, _))
.Times(AnyNumber())
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc
index 85a99ba..3dacb09 100644
--- a/chrome/browser/chromeos/login/login_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -42,8 +42,6 @@ class LoginTestBase : public InProcessBrowserTest {
EXPECT_CALL(mock_input_method_library_, GetActiveInputMethods())
.WillRepeatedly(
InvokeWithoutArgs(CreateFallbackInputMethodDescriptors));
- EXPECT_CALL(mock_input_method_library_, current_ime_properties())
- .WillOnce((ReturnRef(ime_properties_)));
testApi_->SetNetworkLibrary(&mock_network_library_, false);
diff --git a/chrome/browser/chromeos/status/input_method_menu.cc b/chrome/browser/chromeos/status/input_method_menu.cc
new file mode 100644
index 0000000..b672d3d
--- /dev/null
+++ b/chrome/browser/chromeos/status/input_method_menu.cc
@@ -0,0 +1,624 @@
+// Copyright (c) 2010 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/status/input_method_menu.h"
+
+#include <string>
+
+#include <gtk/gtk.h> // for gtk_menu_shell_set_take_focus.
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/keyboard_library.h"
+#include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "chrome/browser/chromeos/language_preferences.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+// The language menu consists of 3 parts (in this order):
+//
+// (1) input method names. The size of the list is always >= 1.
+// (2) input method properties. This list might be empty.
+// (3) "Customize language and input..." button.
+//
+// Example of the menu (Japanese):
+//
+// ============================== (border of the popup window)
+// [ ] English (|index| in the following functions is 0)
+// [*] Japanese
+// [ ] Chinese (Simplified)
+// ------------------------------ (separator)
+// [*] Hiragana (index = 5, The property has 2 radio groups)
+// [ ] Katakana
+// [ ] HalfWidthKatakana
+// [*] Roman
+// [ ] Kana
+// ------------------------------ (separator)
+// Customize language and input...(index = 11)
+// ============================== (border of the popup window)
+//
+// Example of the menu (Simplified Chinese):
+//
+// ============================== (border of the popup window)
+// [ ] English
+// [ ] Japanese
+// [*] Chinese (Simplified)
+// ------------------------------ (separator)
+// Switch to full letter mode (The property has 2 command buttons)
+// Switch to half punctuation mode
+// ------------------------------ (separator)
+// Customize language and input...
+// ============================== (border of the popup window)
+//
+
+namespace {
+
+// Constants to specify the type of items in |model_|.
+enum {
+ COMMAND_ID_INPUT_METHODS = 0, // English, Chinese, Japanese, Arabic, ...
+ COMMAND_ID_IME_PROPERTIES, // Hiragana, Katakana, ...
+ COMMAND_ID_CUSTOMIZE_LANGUAGE, // "Customize language and input..." button.
+};
+
+// A group ID for IME properties starts from 0. We use the huge value for the
+// input method list to avoid conflict.
+const int kRadioGroupLanguage = 1 << 16;
+const int kRadioGroupNone = -1;
+
+// A mapping from an input method id to a string for the language indicator. The
+// mapping is necessary since some input methods belong to the same language.
+// For example, both "xkb:us::eng" and "xkb:us:dvorak:eng" are for US English.
+const struct {
+ const char* input_method_id;
+ const char* indicator_text;
+} kMappingFromIdToIndicatorText[] = {
+ // To distinguish from "xkb:us::eng"
+ { "xkb:us:dvorak:eng", "DV" },
+ // To distinguish from "xkb:jp::jpn"
+ { "mozc", "\xe3\x81\x82" }, // Japanese Hiragana letter A in UTF-8.
+ { "mozc-dv", "\xe3\x81\x82" },
+ { "mozc-jp", "\xe3\x81\x82" },
+ // For simplified Chinese input methods
+ { "pinyin", "\xe6\x8b\xbc" }, // U+62FC
+ // For traditional Chinese input methods
+ { "chewing", "\xe9\x85\xb7" }, // U+9177
+ { "m17n:zh:cangjie", "\xe5\x80\x89" }, // U+5009
+ { "m17n:zh:quick", "\xe9\x80\x9f" }, // U+901F
+ // For Hangul input method.
+ { "hangul", "\xed\x95\x9c" }, // U+D55C
+};
+const size_t kMappingFromIdToIndicatorTextLen =
+ ARRAYSIZE_UNSAFE(kMappingFromIdToIndicatorText);
+
+// Returns the language name for the given |language_code|.
+std::wstring GetLanguageName(const std::string& language_code) {
+ const string16 language_name = l10n_util::GetDisplayNameForLocale(
+ language_code, g_browser_process->GetApplicationLocale(), true);
+ return UTF16ToWide(language_name);
+}
+
+} // namespace
+
+namespace chromeos {
+
+////////////////////////////////////////////////////////////////////////////////
+// InputMethodMenu
+
+InputMethodMenu::InputMethodMenu(PrefService* pref_service,
+ bool is_browser_mode,
+ bool is_screen_locker_mode)
+ : input_method_descriptors_(CrosLibrary::Get()->GetInputMethodLibrary()->
+ GetActiveInputMethods()),
+ model_(NULL),
+ // Be aware that the constructor of |language_menu_| calls GetItemCount()
+ // in this class. Therefore, GetItemCount() have to return 0 when
+ // |model_| is NULL.
+ ALLOW_THIS_IN_INITIALIZER_LIST(language_menu_(this)),
+ minimum_language_menu_width_(0),
+ pref_service_(pref_service),
+ logged_in_(false),
+ is_browser_mode_(is_browser_mode),
+ is_screen_locker_mode_(is_screen_locker_mode) {
+ DCHECK(input_method_descriptors_.get() &&
+ !input_method_descriptors_->empty());
+
+ // Use the same keyboard layout on all windows.
+ CrosLibrary::Get()->GetKeyboardLibrary()->SetKeyboardLayoutPerWindow(false);
+
+ // Sync current and previous input methods on Chrome prefs with ibus-daemon.
+ // InputMethodChanged() will be called soon and the indicator will be updated.
+ InputMethodLibrary* library = CrosLibrary::Get()->GetInputMethodLibrary();
+ if (pref_service && is_browser_mode_) {
+ previous_input_method_pref_.Init(
+ prefs::kLanguagePreviousInputMethod, pref_service, this);
+ const std::string previous_input_method_id =
+ previous_input_method_pref_.GetValue();
+ if (!previous_input_method_id.empty()) {
+ library->ChangeInputMethod(previous_input_method_id);
+ }
+
+ current_input_method_pref_.Init(
+ prefs::kLanguageCurrentInputMethod, pref_service, this);
+ const std::string current_input_method_id =
+ current_input_method_pref_.GetValue();
+ if (!current_input_method_id.empty()) {
+ library->ChangeInputMethod(current_input_method_id);
+ }
+ }
+ library->AddObserver(this);
+
+ if (is_browser_mode_ || is_screen_locker_mode_) {
+ logged_in_ = true;
+ }
+ if (!logged_in_) {
+ registrar_.Add(this,
+ NotificationType::LOGIN_USER_CHANGED,
+ NotificationService::AllSources());
+ }
+}
+
+InputMethodMenu::~InputMethodMenu() {
+ CrosLibrary::Get()->GetInputMethodLibrary()->RemoveObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// menus::MenuModel implementation:
+
+int InputMethodMenu::GetCommandIdAt(int index) const {
+ return 0; // dummy
+}
+
+bool InputMethodMenu::IsLabelDynamicAt(int index) const {
+ // Menu content for the language button could change time by time.
+ return true;
+}
+
+bool InputMethodMenu::GetAcceleratorAt(
+ int index, menus::Accelerator* accelerator) const {
+ // Views for Chromium OS does not support accelerators yet.
+ return false;
+}
+
+bool InputMethodMenu::IsItemCheckedAt(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(input_method_descriptors_.get());
+
+ if (IndexIsInInputMethodList(index)) {
+ const InputMethodDescriptor& input_method
+ = input_method_descriptors_->at(index);
+ return input_method == CrosLibrary::Get()->GetInputMethodLibrary()->
+ current_input_method();
+ }
+
+ if (GetPropertyIndex(index, &index)) {
+ const ImePropertyList& property_list
+ = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
+ return property_list.at(index).is_selection_item_checked;
+ }
+
+ // Separator(s) or the "Customize language and input..." button.
+ return false;
+}
+
+int InputMethodMenu::GetGroupIdAt(int index) const {
+ DCHECK_GE(index, 0);
+
+ if (IndexIsInInputMethodList(index)) {
+ return kRadioGroupLanguage;
+ }
+
+ if (GetPropertyIndex(index, &index)) {
+ const ImePropertyList& property_list
+ = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
+ return property_list.at(index).selection_item_id;
+ }
+
+ return kRadioGroupNone;
+}
+
+bool InputMethodMenu::HasIcons() const {
+ // We don't support icons on Chrome OS.
+ return false;
+}
+
+bool InputMethodMenu::GetIconAt(int index, SkBitmap* icon) const {
+ return false;
+}
+
+menus::ButtonMenuItemModel* InputMethodMenu::GetButtonMenuItemAt(
+ int index) const {
+ return NULL;
+}
+
+bool InputMethodMenu::IsEnabledAt(int index) const {
+ // Just return true so all input method names and input method propertie names
+ // could be clicked.
+ return true;
+}
+
+menus::MenuModel* InputMethodMenu::GetSubmenuModelAt(int index) const {
+ // We don't use nested menus.
+ return NULL;
+}
+
+void InputMethodMenu::HighlightChangedTo(int index) {
+ // Views for Chromium OS does not support this interface yet.
+}
+
+void InputMethodMenu::MenuWillShow() {
+ // Views for Chromium OS does not support this interface yet.
+}
+
+int InputMethodMenu::GetItemCount() const {
+ if (!model_.get()) {
+ // Model is not constructed yet. This means that
+ // InputMethodMenu is being constructed. Return zero.
+ return 0;
+ }
+ return model_->GetItemCount();
+}
+
+menus::MenuModel::ItemType InputMethodMenu::GetTypeAt(int index) const {
+ DCHECK_GE(index, 0);
+
+ if (IndexPointsToConfigureImeMenuItem(index)) {
+ return menus::MenuModel::TYPE_COMMAND; // "Customize language and input"
+ }
+
+ if (IndexIsInInputMethodList(index)) {
+ return menus::MenuModel::TYPE_RADIO;
+ }
+
+ if (GetPropertyIndex(index, &index)) {
+ const ImePropertyList& property_list
+ = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
+ if (property_list.at(index).is_selection_item) {
+ return menus::MenuModel::TYPE_RADIO;
+ }
+ return menus::MenuModel::TYPE_COMMAND;
+ }
+
+ return menus::MenuModel::TYPE_SEPARATOR;
+}
+
+string16 InputMethodMenu::GetLabelAt(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(input_method_descriptors_.get());
+
+ // We use IDS_OPTIONS_SETTINGS_LANGUAGES_CUSTOMIZE here as the button
+ // opens the same dialog that is opened from the main options dialog.
+ if (IndexPointsToConfigureImeMenuItem(index)) {
+ return l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CUSTOMIZE);
+ }
+
+ std::wstring name;
+ if (IndexIsInInputMethodList(index)) {
+ name = GetTextForMenu(input_method_descriptors_->at(index));
+ } else if (GetPropertyIndex(index, &index)) {
+ const ImePropertyList& property_list
+ = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
+ return input_method::GetStringUTF16(property_list.at(index).label);
+ }
+
+ return WideToUTF16(name);
+}
+
+void InputMethodMenu::ActivatedAt(int index) {
+ DCHECK_GE(index, 0);
+ DCHECK(input_method_descriptors_.get());
+
+ if (IndexPointsToConfigureImeMenuItem(index)) {
+ OpenConfigUI();
+ return;
+ }
+
+ if (IndexIsInInputMethodList(index)) {
+ // Inter-IME switching.
+ const InputMethodDescriptor& input_method
+ = input_method_descriptors_->at(index);
+ CrosLibrary::Get()->GetInputMethodLibrary()->ChangeInputMethod(
+ input_method.id);
+ return;
+ }
+
+ if (GetPropertyIndex(index, &index)) {
+ // Intra-IME switching (e.g. Japanese-Hiragana to Japanese-Katakana).
+ const ImePropertyList& property_list
+ = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
+ const std::string key = property_list.at(index).key;
+ if (property_list.at(index).is_selection_item) {
+ // Radio button is clicked.
+ const int id = property_list.at(index).selection_item_id;
+ // First, deactivate all other properties in the same radio group.
+ for (int i = 0; i < static_cast<int>(property_list.size()); ++i) {
+ if (i != index && id == property_list.at(i).selection_item_id) {
+ CrosLibrary::Get()->GetInputMethodLibrary()->SetImePropertyActivated(
+ property_list.at(i).key, false);
+ }
+ }
+ // Then, activate the property clicked.
+ CrosLibrary::Get()->GetInputMethodLibrary()->SetImePropertyActivated(
+ key, true);
+ } else {
+ // Command button like "Switch to half punctuation mode" is clicked.
+ // We can always use "Deactivate" for command buttons.
+ CrosLibrary::Get()->GetInputMethodLibrary()->SetImePropertyActivated(
+ key, false);
+ }
+ return;
+ }
+
+ LOG(ERROR) << "Unexpected index: " << index;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// views::ViewMenuDelegate implementation:
+
+void InputMethodMenu::RunMenu(
+ views::View* unused_source, const gfx::Point& pt) {
+ UserMetrics::RecordAction(UserMetricsAction("LanguageMenuButton_Open"));
+ input_method_descriptors_.reset(CrosLibrary::Get()->GetInputMethodLibrary()->
+ GetActiveInputMethods());
+ RebuildModel();
+ language_menu_.Rebuild();
+
+ // Disallow the menu widget to grab the keyboard focus. This is necessary to
+ // enable users to change status of an input method (e.g. change the input
+ // mode from Japanese Hiragana to Japanese Katakana) without discarding a
+ // preedit string. See crosbug.com/5796 for details. Note that menus other
+ // than this one should not call the Gtk+ API since it is a special API only
+ // for a menu related to IME/keyboard. See the Gtk+ API reference at:
+ // http://library.gnome.org/devel/gtk/stable/GtkMenuShell.html
+ gfx::NativeMenu native_menu = language_menu_.GetNativeMenu();
+ if (native_menu) {
+ gtk_menu_shell_set_take_focus(GTK_MENU_SHELL(native_menu), FALSE);
+ } else {
+ LOG(ERROR)
+ << "Can't call gtk_menu_shell_set_take_focus since NativeMenu is NULL";
+ }
+
+ language_menu_.UpdateStates();
+ if (minimum_language_menu_width_ > 0) {
+ language_menu_.SetMinimumWidth(minimum_language_menu_width_);
+ }
+ language_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// InputMethodLibrary::Observer implementation:
+
+void InputMethodMenu::InputMethodChanged(InputMethodLibrary* obj) {
+ UserMetrics::RecordAction(
+ UserMetricsAction("LanguageMenuButton_InputMethodChanged"));
+
+ const InputMethodDescriptor& previous_input_method =
+ obj->previous_input_method();
+ const InputMethodDescriptor& current_input_method =
+ obj->current_input_method();
+ UpdateUIFromInputMethod(current_input_method);
+ // Update Chrome prefs as well.
+ if (is_browser_mode_) {
+ if (pref_service_) { // make sure we're not in unit tests.
+ // Sometimes (e.g. initial boot) |previous_input_method.id| is empty.
+ previous_input_method_pref_.SetValue(previous_input_method.id);
+ current_input_method_pref_.SetValue(current_input_method.id);
+ }
+ } else {
+ // We're in the login screen (i.e. not in the normal browser mode nor screen
+ // locker mode). If a user has already logged in, we should not update the
+ // local state since a profile for the user might be loaded before the
+ // buttun for the login screen is destroyed.
+ if (!logged_in_ && g_browser_process && g_browser_process->local_state()) {
+ g_browser_process->local_state()->SetString(
+ language_prefs::kPreferredKeyboardLayout, current_input_method.id);
+ g_browser_process->local_state()->SavePersistentPrefs();
+ }
+ }
+}
+
+void InputMethodMenu::ActiveInputMethodsChanged(InputMethodLibrary* obj) {
+ // Update the icon if active input methods are changed. See also
+ // comments in UpdateUI()
+ UpdateUIFromInputMethod(obj->current_input_method());
+}
+
+void InputMethodMenu::ImePropertiesChanged(InputMethodLibrary* obj) {
+}
+
+void InputMethodMenu::UpdateUIFromInputMethod(
+ const InputMethodDescriptor& input_method) {
+ const std::wstring name = GetTextForIndicator(input_method);
+ const std::wstring tooltip = GetTextForMenu(input_method);
+ UpdateUI(name, tooltip);
+}
+
+void InputMethodMenu::RebuildModel() {
+ model_.reset(new menus::SimpleMenuModel(NULL));
+ string16 dummy_label = UTF8ToUTF16("");
+ // Indicates if separator's needed before each section.
+ bool need_separator = false;
+
+ if (!input_method_descriptors_->empty()) {
+ // We "abuse" the command_id and group_id arguments of AddRadioItem method.
+ // A COMMAND_ID_XXX enum value is passed as command_id, and array index of
+ // |input_method_descriptors_| or |property_list| is passed as group_id.
+ for (size_t i = 0; i < input_method_descriptors_->size(); ++i) {
+ model_->AddRadioItem(COMMAND_ID_INPUT_METHODS, dummy_label, i);
+ }
+
+ need_separator = true;
+ }
+
+ const ImePropertyList& property_list
+ = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
+ if (!property_list.empty()) {
+ if (need_separator) {
+ model_->AddSeparator();
+ }
+ for (size_t i = 0; i < property_list.size(); ++i) {
+ model_->AddRadioItem(COMMAND_ID_IME_PROPERTIES, dummy_label, i);
+ }
+ need_separator = true;
+ }
+
+ if (ShouldSupportConfigUI()) {
+ // Note: We use AddSeparator() for separators, and AddRadioItem() for all
+ // other items even if an item is not actually a radio item.
+ if (need_separator) {
+ model_->AddSeparator();
+ }
+ model_->AddRadioItem(COMMAND_ID_CUSTOMIZE_LANGUAGE, dummy_label,
+ 0 /* dummy */);
+ }
+}
+
+bool InputMethodMenu::IndexIsInInputMethodList(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(model_.get());
+ if (index >= model_->GetItemCount()) {
+ return false;
+ }
+
+ return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
+ (model_->GetCommandIdAt(index) == COMMAND_ID_INPUT_METHODS) &&
+ input_method_descriptors_.get() &&
+ (index < static_cast<int>(input_method_descriptors_->size())));
+}
+
+bool InputMethodMenu::GetPropertyIndex(int index, int* property_index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(property_index);
+ DCHECK(model_.get());
+ if (index >= model_->GetItemCount()) {
+ return false;
+ }
+
+ if ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
+ (model_->GetCommandIdAt(index) == COMMAND_ID_IME_PROPERTIES)) {
+ const int tmp_property_index = model_->GetGroupIdAt(index);
+ const ImePropertyList& property_list
+ = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
+ if (tmp_property_index < static_cast<int>(property_list.size())) {
+ *property_index = tmp_property_index;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool InputMethodMenu::IndexPointsToConfigureImeMenuItem(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(model_.get());
+ if (index >= model_->GetItemCount()) {
+ return false;
+ }
+
+ return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
+ (model_->GetCommandIdAt(index) == COMMAND_ID_CUSTOMIZE_LANGUAGE));
+}
+
+std::wstring InputMethodMenu::GetTextForIndicator(
+ const InputMethodDescriptor& input_method) {
+ // For the status area, we use two-letter, upper-case language code like
+ // "US" and "JP".
+ std::wstring text;
+
+ // Check special cases first.
+ for (size_t i = 0; i < kMappingFromIdToIndicatorTextLen; ++i) {
+ if (kMappingFromIdToIndicatorText[i].input_method_id == input_method.id) {
+ text = UTF8ToWide(kMappingFromIdToIndicatorText[i].indicator_text);
+ break;
+ }
+ }
+
+ // Display the keyboard layout name when using ibus-xkb.
+ if (text.empty()) {
+ const size_t kMaxKeyboardLayoutNameLen = 2;
+ const std::wstring keyboard_layout = UTF8ToWide(
+ input_method::GetKeyboardLayoutName(input_method.id));
+ text = StringToUpperASCII(keyboard_layout).substr(
+ 0, kMaxKeyboardLayoutNameLen);
+ }
+
+ // TODO(yusukes): Some languages have two or more input methods. For example,
+ // Thai has 3, Vietnamese has 4. If these input methods could be activated at
+ // the same time, we should do either of the following:
+ // (1) Add mappings to |kMappingFromIdToIndicatorText|
+ // (2) Add suffix (1, 2, ...) to |text| when ambiguous.
+
+ if (text.empty()) {
+ const size_t kMaxLanguageNameLen = 2;
+ std::string language_code =
+ input_method::GetLanguageCodeFromDescriptor(input_method);
+
+ // Use "CN" for simplified Chinese and "TW" for traditonal Chinese,
+ // rather than "ZH".
+ if (StartsWithASCII(language_code, "zh-", false)) {
+ std::vector<std::string> portions;
+ SplitString(language_code, '-', &portions);
+ if (portions.size() >= 2 && !portions[1].empty()) {
+ language_code = portions[1];
+ }
+ }
+
+ text = StringToUpperASCII(UTF8ToWide(language_code)).substr(
+ 0, kMaxLanguageNameLen);
+ }
+ DCHECK(!text.empty());
+ return text;
+}
+
+std::wstring InputMethodMenu::GetTextForMenu(
+ const InputMethodDescriptor& input_method) {
+ // We don't show language here. Name of keyboard layout or input method
+ // usually imply (or explicitly include) its language.
+
+ // Special case for Dutch, French and German: these languages have multiple
+ // keyboard layouts and share the same laout of keyboard (Belgian). We need to
+ // show explicitly the language for the layout.
+ // For Arabic and Hindi: they share "Standard Input Method".
+ const std::string language_code
+ = input_method::GetLanguageCodeFromDescriptor(input_method);
+ std::wstring text;
+ if (language_code == "ar" ||
+ language_code == "hi" ||
+ language_code == "nl" ||
+ language_code == "fr" ||
+ language_code == "de") {
+ text = GetLanguageName(language_code) + L" - ";
+ }
+ text += input_method::GetString(input_method.display_name);
+
+ DCHECK(!text.empty());
+ return text;
+}
+
+void InputMethodMenu::RegisterPrefs(PrefService* local_state) {
+ local_state->RegisterStringPref(language_prefs::kPreferredKeyboardLayout, "");
+}
+
+void InputMethodMenu::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::LOGIN_USER_CHANGED) {
+ logged_in_ = true;
+ }
+}
+
+void InputMethodMenu::SetMinimumWidth(int width) {
+ // On the OOBE network selection screen, fixed width menu would be preferable.
+ minimum_language_menu_width_ = width;
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/status/input_method_menu.h b/chrome/browser/chromeos/status/input_method_menu.h
new file mode 100644
index 0000000..c91d885
--- /dev/null
+++ b/chrome/browser/chromeos/status/input_method_menu.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_STATUS_INPUT_METHOD_MENU_H_
+#define CHROME_BROWSER_CHROMEOS_STATUS_INPUT_METHOD_MENU_H_
+#pragma once
+
+#include "app/menus/simple_menu_model.h"
+#include "chrome/browser/chromeos/cros/input_method_library.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "views/controls/menu/menu_2.h"
+#include "views/controls/menu/view_menu_delegate.h"
+
+class PrefService;
+class SkBitmap;
+
+namespace chromeos {
+
+// A class for the dropdown menu for switching input method and keyboard layout.
+// Since the class provides the views::ViewMenuDelegate interface, it's easy to
+// create a button widget (e.g. views::MenuButton, chromeos::StatusAreaButton)
+// which shows the dropdown menu on click.
+class InputMethodMenu : public views::ViewMenuDelegate,
+ public menus::MenuModel,
+ public InputMethodLibrary::Observer,
+ public NotificationObserver {
+ public:
+ InputMethodMenu(PrefService* pref_service,
+ bool is_browser_mode,
+ bool is_screen_locker);
+ virtual ~InputMethodMenu();
+
+ // menus::MenuModel implementation.
+ virtual bool HasIcons() const;
+ virtual int GetItemCount() const;
+ virtual menus::MenuModel::ItemType GetTypeAt(int index) const;
+ virtual int GetCommandIdAt(int index) const;
+ virtual string16 GetLabelAt(int index) const;
+ virtual bool IsLabelDynamicAt(int index) const;
+ virtual bool GetAcceleratorAt(int index,
+ menus::Accelerator* accelerator) const;
+ virtual bool IsItemCheckedAt(int index) const;
+ virtual int GetGroupIdAt(int index) const;
+ virtual bool GetIconAt(int index, SkBitmap* icon) const;
+ virtual menus::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const;
+ virtual bool IsEnabledAt(int index) const;
+ virtual menus::MenuModel* GetSubmenuModelAt(int index) const;
+ virtual void HighlightChangedTo(int index);
+ virtual void ActivatedAt(int index);
+ virtual void MenuWillShow();
+
+ // views::ViewMenuDelegate implementation. Sub classes can override the method
+ // to adjust the position of the menu.
+ virtual void RunMenu(views::View* unused_source, const gfx::Point& pt);
+
+ // InputMethodLibrary::Observer implementation.
+ virtual void InputMethodChanged(InputMethodLibrary* obj);
+ virtual void ImePropertiesChanged(InputMethodLibrary* obj);
+ virtual void ActiveInputMethodsChanged(InputMethodLibrary* obj);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Sets the minimum width of the dropdown menu.
+ void SetMinimumWidth(int width);
+
+ // Registers input method preferences for the login screen.
+ static void RegisterPrefs(PrefService* local_state);
+
+ // Returns a string for the indicator on top right corner of the Chrome
+ // window. The method is public for unit tests.
+ static std::wstring GetTextForIndicator(
+ const InputMethodDescriptor& input_method);
+
+ // Returns a string for the drop-down menu and the tooltip for the indicator.
+ // The method is public for unit tests.
+ static std::wstring GetTextForMenu(const InputMethodDescriptor& input_method);
+
+ protected:
+ // Parses |input_method| and then calls UpdateUI().
+ void UpdateUIFromInputMethod(const InputMethodDescriptor& input_method);
+
+ private:
+ // Updates UI of a container of the menu (e.g. the "US" menu button in the
+ // status area). Sub classes have to implement the interface for their own UI.
+ virtual void UpdateUI(
+ const std::wstring& name, const std::wstring& tooltip) = 0;
+
+ // Sub classes have to implement the interface. This interface should return
+ // true if the dropdown menu should show an item like "Customize languages
+ // and input..." DOMUI.
+ virtual bool ShouldSupportConfigUI() = 0;
+
+ // Sub classes have to implement the interface which opens an UI for
+ // customizing languages and input.
+ virtual void OpenConfigUI() = 0;
+
+ // Rebuilds |model_|. This function should be called whenever
+ // |input_method_descriptors_| is updated, or ImePropertiesChanged() is
+ // called.
+ void RebuildModel();
+
+ // Returns true if the zero-origin |index| points to one of the input methods.
+ bool IndexIsInInputMethodList(int index) const;
+
+ // Returns true if the zero-origin |index| points to one of the IME
+ // properties. When returning true, |property_index| is updated so that
+ // property_list.at(property_index) points to the menu item.
+ bool GetPropertyIndex(int index, int* property_index) const;
+
+ // Returns true if the zero-origin |index| points to the "Configure IME" menu
+ // item.
+ bool IndexPointsToConfigureImeMenuItem(int index) const;
+
+ // The current input method list.
+ scoped_ptr<InputMethodDescriptors> input_method_descriptors_;
+
+ // Objects for reading/writing the Chrome prefs.
+ StringPrefMember previous_input_method_pref_;
+ StringPrefMember current_input_method_pref_;
+
+ // We borrow menus::SimpleMenuModel implementation to maintain the current
+ // content of the pop-up menu. The menus::MenuModel is implemented using this
+ // |model_|.
+ scoped_ptr<menus::SimpleMenuModel> model_;
+
+ // The language menu which pops up when the button in status area is clicked.
+ views::Menu2 language_menu_;
+ int minimum_language_menu_width_;
+
+ PrefService* pref_service_;
+ NotificationRegistrar registrar_;
+ bool logged_in_;
+ const bool is_browser_mode_;
+ const bool is_screen_locker_mode_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputMethodMenu);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_STATUS_INPUT_METHOD_MENU_H_
diff --git a/chrome/browser/chromeos/status/language_menu_button_unittest.cc b/chrome/browser/chromeos/status/input_method_menu_unittest.cc
index b760fbc..3d194b7 100644
--- a/chrome/browser/chromeos/status/language_menu_button_unittest.cc
+++ b/chrome/browser/chromeos/status/input_method_menu_unittest.cc
@@ -2,105 +2,105 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/chromeos/status/language_menu_button.h"
+#include "chrome/browser/chromeos/status/input_method_menu.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
-TEST(LanguageMenuButtonTest, GetTextForIndicatorTest) {
+TEST(InputMethodMenuTest, GetTextForIndicatorTest) {
// Test normal cases. Two-letter language code should be returned.
{
InputMethodDescriptor desc("m17n:fa:isiri", // input method engine id
"isiri (m17n)", // input method name
"us", // keyboard layout name
"fa"); // language name
- EXPECT_EQ(L"FA", LanguageMenuButton::GetTextForIndicator(desc));
+ EXPECT_EQ(L"FA", InputMethodMenu::GetTextForIndicator(desc));
}
{
InputMethodDescriptor desc("hangul", "Korean", "us", "ko");
EXPECT_EQ(UTF8ToWide("\xed\x95\x9c"),
- LanguageMenuButton::GetTextForIndicator(desc));
+ InputMethodMenu::GetTextForIndicator(desc));
}
{
InputMethodDescriptor desc("invalid-id", "unregistered string", "us", "xx");
// Upper-case string of the unknown language code, "xx", should be returned.
- EXPECT_EQ(L"XX", LanguageMenuButton::GetTextForIndicator(desc));
+ EXPECT_EQ(L"XX", InputMethodMenu::GetTextForIndicator(desc));
}
// Test special cases.
{
InputMethodDescriptor desc("xkb:us:dvorak:eng", "Dvorak", "us", "eng");
- EXPECT_EQ(L"DV", LanguageMenuButton::GetTextForIndicator(desc));
+ EXPECT_EQ(L"DV", InputMethodMenu::GetTextForIndicator(desc));
}
{
InputMethodDescriptor desc("mozc", "Mozc", "us", "ja");
EXPECT_EQ(UTF8ToWide("\xe3\x81\x82"),
- LanguageMenuButton::GetTextForIndicator(desc));
+ InputMethodMenu::GetTextForIndicator(desc));
}
{
InputMethodDescriptor desc("mozc-jp", "Mozc", "jp", "ja");
EXPECT_EQ(UTF8ToWide("\xe3\x81\x82"),
- LanguageMenuButton::GetTextForIndicator(desc));
+ InputMethodMenu::GetTextForIndicator(desc));
}
{
InputMethodDescriptor desc("pinyin", "Pinyin", "us", "zh-CN");
EXPECT_EQ(UTF8ToWide("\xe6\x8b\xbc"),
- LanguageMenuButton::GetTextForIndicator(desc));
+ InputMethodMenu::GetTextForIndicator(desc));
}
{
InputMethodDescriptor desc("chewing", "Chewing", "us", "zh-TW");
EXPECT_EQ(UTF8ToWide("\xe9\x85\xb7"),
- LanguageMenuButton::GetTextForIndicator(desc));
+ InputMethodMenu::GetTextForIndicator(desc));
}
{
InputMethodDescriptor desc("m17n:zh:cangjie", "Cangjie", "us", "zh-TW");
EXPECT_EQ(UTF8ToWide("\xe5\x80\x89"),
- LanguageMenuButton::GetTextForIndicator(desc));
+ InputMethodMenu::GetTextForIndicator(desc));
}
{
InputMethodDescriptor desc("m17n:zh:quick", "Quick", "us", "zh-TW");
EXPECT_EQ(UTF8ToWide("\xe9\x80\x9f"),
- LanguageMenuButton::GetTextForIndicator(desc));
+ InputMethodMenu::GetTextForIndicator(desc));
}
}
// Test whether the function returns language name for non-ambiguous languages.
-TEST(LanguageMenuButtonTest, GetTextForMenuTest) {
+TEST(InputMethodMenuTest, GetTextForMenuTest) {
// For most languages input method or keyboard layout name is returned.
// See below for exceptions.
{
InputMethodDescriptor desc("m17n:fa:isiri", "isiri (m17n)", "us", "fa");
EXPECT_EQ(L"Persian input method (ISIRI 2901 layout)",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("hangul", "Korean", "us", "ko");
EXPECT_EQ(L"Korean input method",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("m17n:vi:tcvn", "tcvn (m17n)", "us", "vi");
EXPECT_EQ(L"Vietnamese input method (TCVN6064)",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("mozc", "Mozc (US keyboard layout)", "us", "ja");
EXPECT_EQ(L"Japanese input method (for US keyboard)",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("xkb:jp::jpn", "Japan", "jp", "jpn");
EXPECT_EQ(L"Japanese keyboard layout",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("xkb:us:dvorak:eng", "USA - Dvorak",
"us(dvorak)", "eng");
EXPECT_EQ(L"English (Dvorak)",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
// For Arabic, Dutch, French, German and Hindi,
@@ -108,42 +108,42 @@ TEST(LanguageMenuButtonTest, GetTextForMenuTest) {
{
InputMethodDescriptor desc("m17n:ar:kbd", "kbd (m17n)", "us", "ar");
EXPECT_EQ(L"Arabic - Standard input method",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("xkb:nl::nld", "Netherlands", "nl", "nld");
EXPECT_EQ(L"Dutch - Dutch keyboard layout",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("xkb:be::nld", "Belgium", "be", "nld");
EXPECT_EQ(L"Dutch - Belgian keyboard layout",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("xkb:fr::fra", "France", "fr", "fra");
EXPECT_EQ(L"French - French keyboard layout",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("xkb:be::fra", "Belgium", "be", "fra");
EXPECT_EQ(L"French - Belgian keyboard layout",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("xkb:de::ger", "Germany", "de", "ger");
EXPECT_EQ(L"German - German keyboard layout",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("xkb:be::ger", "Belgium", "be", "ger");
EXPECT_EQ(L"German - Belgian keyboard layout",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("m17n:hi:itrans", "itrans (m17n)", "us", "hi");
EXPECT_EQ(L"Hindi - Standard input method",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
{
@@ -151,7 +151,7 @@ TEST(LanguageMenuButtonTest, GetTextForMenuTest) {
// You can safely ignore the "Resouce ID is not found for: unregistered
// string" error.
EXPECT_EQ(L"unregistered string",
- LanguageMenuButton::GetTextForMenu(desc));
+ InputMethodMenu::GetTextForMenu(desc));
}
}
diff --git a/chrome/browser/chromeos/status/language_menu_button.cc b/chrome/browser/chromeos/status/language_menu_button.cc
index 24f2da5..53eef99 100644
--- a/chrome/browser/chromeos/status/language_menu_button.cc
+++ b/chrome/browser/chromeos/status/language_menu_button.cc
@@ -6,107 +6,16 @@
#include <string>
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "base/string_split.h"
-#include "base/string_util.h"
-#include "base/time.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/keyboard_library.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
-#include "chrome/browser/chromeos/language_preferences.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
-#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
-#include "chrome/common/pref_names.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-
-// The language menu consists of 3 parts (in this order):
-//
-// (1) input method names. The size of the list is always >= 1.
-// (2) input method properties. This list might be empty.
-// (3) "Customize language and input..." button.
-//
-// Example of the menu (Japanese):
-//
-// ============================== (border of the popup window)
-// [ ] English (|index| in the following functions is 0)
-// [*] Japanese
-// [ ] Chinese (Simplified)
-// ------------------------------ (separator)
-// [*] Hiragana (index = 5, The property has 2 radio groups)
-// [ ] Katakana
-// [ ] HalfWidthKatakana
-// [*] Roman
-// [ ] Kana
-// ------------------------------ (separator)
-// Customize language and input...(index = 11)
-// ============================== (border of the popup window)
-//
-// Example of the menu (Simplified Chinese):
-//
-// ============================== (border of the popup window)
-// [ ] English
-// [ ] Japanese
-// [*] Chinese (Simplified)
-// ------------------------------ (separator)
-// Switch to full letter mode (The property has 2 command buttons)
-// Switch to half punctuation mode
-// ------------------------------ (separator)
-// Customize language and input...
-// ============================== (border of the popup window)
-//
namespace {
-// Constants to specify the type of items in |model_|.
-enum {
- COMMAND_ID_INPUT_METHODS = 0, // English, Chinese, Japanese, Arabic, ...
- COMMAND_ID_IME_PROPERTIES, // Hiragana, Katakana, ...
- COMMAND_ID_CUSTOMIZE_LANGUAGE, // "Customize language and input..." button.
-};
-
-// A group ID for IME properties starts from 0. We use the huge value for the
-// input method list to avoid conflict.
-const int kRadioGroupLanguage = 1 << 16;
-const int kRadioGroupNone = -1;
-
-// A mapping from an input method id to a text for the language indicator. The
-// mapping is necessary since some input methods belong to the same language.
-// For example, both "xkb:us::eng" and "xkb:us:dvorak:eng" are for US English.
-const struct {
- const char* input_method_id;
- const char* indicator_text;
-} kMappingFromIdToIndicatorText[] = {
- // To distinguish from "xkb:us::eng"
- { "xkb:us:dvorak:eng", "DV" },
- // To distinguish from "xkb:jp::jpn"
- { "mozc", "\xe3\x81\x82" }, // Japanese Hiragana letter A in UTF-8.
- { "mozc-dv", "\xe3\x81\x82" },
- { "mozc-jp", "\xe3\x81\x82" },
- // For simplified Chinese input methods
- { "pinyin", "\xe6\x8b\xbc" }, // U+62FC
- // For traditional Chinese input methods
- { "chewing", "\xe9\x85\xb7" }, // U+9177
- { "m17n:zh:cangjie", "\xe5\x80\x89" }, // U+5009
- { "m17n:zh:quick", "\xe9\x80\x9f" }, // U+901F
- // For Hangul input method.
- { "hangul", "\xed\x95\x9c" }, // U+D55C
-};
-const size_t kMappingFromIdToIndicatorTextLen =
- ARRAYSIZE_UNSAFE(kMappingFromIdToIndicatorText);
-
-// Returns the language name for the given |language_code|.
-std::wstring GetLanguageName(const std::string& language_code) {
- const string16 language_name = l10n_util::GetDisplayNameForLocale(
- language_code, g_browser_process->GetApplicationLocale(), true);
- return UTF16ToWide(language_name);
-}
-
// Returns PrefService object associated with |host|. Returns NULL if we are NOT
// within a browser.
PrefService* GetPrefService(chromeos::StatusAreaHost* host) {
@@ -125,17 +34,10 @@ namespace chromeos {
LanguageMenuButton::LanguageMenuButton(StatusAreaHost* host)
: StatusAreaButton(this),
- input_method_descriptors_(CrosLibrary::Get()->GetInputMethodLibrary()->
- GetActiveInputMethods()),
- model_(NULL),
- // Be aware that the constructor of |language_menu_| calls GetItemCount()
- // in this class. Therefore, GetItemCount() have to return 0 when
- // |model_| is NULL.
- ALLOW_THIS_IN_INITIALIZER_LIST(language_menu_(this)),
- host_(host),
- logged_in_(false) {
- DCHECK(input_method_descriptors_.get() &&
- !input_method_descriptors_->empty());
+ InputMethodMenu(GetPrefService(host),
+ host->IsBrowserMode(),
+ host->IsScreenLockerMode()),
+ host_(host) {
set_border(NULL);
set_use_menu_button_paint(true);
SetFont(ResourceBundle::GetSharedInstance().GetFont(
@@ -145,312 +47,11 @@ LanguageMenuButton::LanguageMenuButton(StatusAreaHost* host)
SetShowMultipleIconStates(false);
set_alignment(TextButton::ALIGN_CENTER);
- // Update the model
- RebuildModel();
-
// Draw the default indicator "US". The default indicator "US" is used when
// |pref_service| is not available (for example, unit tests) or |pref_service|
// is available, but Chrome preferences are not available (for example,
// initial OS boot).
- UpdateIndicator(L"US", L"");
-
- // Use the same keyboard layout on all windows.
- CrosLibrary::Get()->GetKeyboardLibrary()->SetKeyboardLayoutPerWindow(false);
-
- // Sync current and previous input methods on Chrome prefs with ibus-daemon.
- // InputMethodChanged() will be called soon and the indicator will be updated.
- InputMethodLibrary* library = CrosLibrary::Get()->GetInputMethodLibrary();
- PrefService* pref_service = GetPrefService(host_);
- if (pref_service && host_->IsBrowserMode()) {
- previous_input_method_pref_.Init(
- prefs::kLanguagePreviousInputMethod, pref_service, this);
- const std::string previous_input_method_id =
- previous_input_method_pref_.GetValue();
- if (!previous_input_method_id.empty())
- library->ChangeInputMethod(previous_input_method_id);
-
- current_input_method_pref_.Init(
- prefs::kLanguageCurrentInputMethod, pref_service, this);
- const std::string current_input_method_id =
- current_input_method_pref_.GetValue();
- if (!current_input_method_id.empty())
- library->ChangeInputMethod(current_input_method_id);
- }
- library->AddObserver(this);
-
- if (host_->IsBrowserMode() || host_->IsScreenLockerMode()) {
- logged_in_ = true;
- }
- if (!logged_in_) {
- registrar_.Add(this,
- NotificationType::LOGIN_USER_CHANGED,
- NotificationService::AllSources());
- }
-}
-
-LanguageMenuButton::~LanguageMenuButton() {
- CrosLibrary::Get()->GetInputMethodLibrary()->RemoveObserver(this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// LanguageMenuButton, menus::MenuModel implementation:
-
-int LanguageMenuButton::GetCommandIdAt(int index) const {
- return 0; // dummy
-}
-
-bool LanguageMenuButton::IsLabelDynamicAt(int index) const {
- // Menu content for the language button could change time by time.
- return true;
-}
-
-bool LanguageMenuButton::GetAcceleratorAt(
- int index, menus::Accelerator* accelerator) const {
- // Views for Chromium OS does not support accelerators yet.
- return false;
-}
-
-bool LanguageMenuButton::IsItemCheckedAt(int index) const {
- DCHECK_GE(index, 0);
- DCHECK(input_method_descriptors_.get());
-
- if (IndexIsInInputMethodList(index)) {
- const InputMethodDescriptor& input_method
- = input_method_descriptors_->at(index);
- return input_method == CrosLibrary::Get()->GetInputMethodLibrary()->
- current_input_method();
- }
-
- if (GetPropertyIndex(index, &index)) {
- const ImePropertyList& property_list
- = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
- return property_list.at(index).is_selection_item_checked;
- }
-
- // Separator(s) or the "Customize language and input..." button.
- return false;
-}
-
-int LanguageMenuButton::GetGroupIdAt(int index) const {
- DCHECK_GE(index, 0);
-
- if (IndexIsInInputMethodList(index)) {
- return kRadioGroupLanguage;
- }
-
- if (GetPropertyIndex(index, &index)) {
- const ImePropertyList& property_list
- = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
- return property_list.at(index).selection_item_id;
- }
-
- return kRadioGroupNone;
-}
-
-bool LanguageMenuButton::HasIcons() const {
- // We don't support icons on Chrome OS.
- return false;
-}
-
-bool LanguageMenuButton::GetIconAt(int index, SkBitmap* icon) const {
- return false;
-}
-
-menus::ButtonMenuItemModel* LanguageMenuButton::GetButtonMenuItemAt(
- int index) const {
- return NULL;
-}
-
-bool LanguageMenuButton::IsEnabledAt(int index) const {
- // Just return true so all input method names and input method propertie names
- // could be clicked.
- return true;
-}
-
-menus::MenuModel* LanguageMenuButton::GetSubmenuModelAt(int index) const {
- // We don't use nested menus.
- return NULL;
-}
-
-void LanguageMenuButton::HighlightChangedTo(int index) {
- // Views for Chromium OS does not support this interface yet.
-}
-
-void LanguageMenuButton::MenuWillShow() {
- // Views for Chromium OS does not support this interface yet.
-}
-
-int LanguageMenuButton::GetItemCount() const {
- if (!model_.get()) {
- // Model is not constructed yet. This means that LanguageMenuButton is
- // being constructed. Return zero.
- return 0;
- }
- return model_->GetItemCount();
-}
-
-menus::MenuModel::ItemType LanguageMenuButton::GetTypeAt(int index) const {
- DCHECK_GE(index, 0);
-
- if (IndexPointsToConfigureImeMenuItem(index)) {
- return menus::MenuModel::TYPE_COMMAND; // "Customize language and input"
- }
-
- if (IndexIsInInputMethodList(index)) {
- return menus::MenuModel::TYPE_RADIO;
- }
-
- if (GetPropertyIndex(index, &index)) {
- const ImePropertyList& property_list
- = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
- if (property_list.at(index).is_selection_item) {
- return menus::MenuModel::TYPE_RADIO;
- }
- return menus::MenuModel::TYPE_COMMAND;
- }
-
- return menus::MenuModel::TYPE_SEPARATOR;
-}
-
-string16 LanguageMenuButton::GetLabelAt(int index) const {
- DCHECK_GE(index, 0);
- DCHECK(input_method_descriptors_.get());
-
- // We use IDS_OPTIONS_SETTINGS_LANGUAGES_CUSTOMIZE here as the button
- // opens the same dialog that is opened from the main options dialog.
- if (IndexPointsToConfigureImeMenuItem(index)) {
- return l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CUSTOMIZE);
- }
-
- std::wstring name;
- if (IndexIsInInputMethodList(index)) {
- name = GetTextForMenu(input_method_descriptors_->at(index));
- } else if (GetPropertyIndex(index, &index)) {
- const ImePropertyList& property_list
- = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
- return input_method::GetStringUTF16(property_list.at(index).label);
- }
-
- return WideToUTF16(name);
-}
-
-void LanguageMenuButton::ActivatedAt(int index) {
- DCHECK_GE(index, 0);
- DCHECK(input_method_descriptors_.get());
-
- if (IndexPointsToConfigureImeMenuItem(index)) {
- host_->OpenButtonOptions(this);
- return;
- }
-
- if (IndexIsInInputMethodList(index)) {
- // Inter-IME switching.
- const InputMethodDescriptor& input_method
- = input_method_descriptors_->at(index);
- CrosLibrary::Get()->GetInputMethodLibrary()->ChangeInputMethod(
- input_method.id);
- return;
- }
-
- if (GetPropertyIndex(index, &index)) {
- // Intra-IME switching (e.g. Japanese-Hiragana to Japanese-Katakana).
- const ImePropertyList& property_list
- = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
- const std::string key = property_list.at(index).key;
- if (property_list.at(index).is_selection_item) {
- // Radio button is clicked.
- const int id = property_list.at(index).selection_item_id;
- // First, deactivate all other properties in the same radio group.
- for (int i = 0; i < static_cast<int>(property_list.size()); ++i) {
- if (i != index && id == property_list.at(i).selection_item_id) {
- CrosLibrary::Get()->GetInputMethodLibrary()->SetImePropertyActivated(
- property_list.at(i).key, false);
- }
- }
- // Then, activate the property clicked.
- CrosLibrary::Get()->GetInputMethodLibrary()->SetImePropertyActivated(
- key, true);
- } else {
- // Command button like "Switch to half punctuation mode" is clicked.
- // We can always use "Deactivate" for command buttons.
- CrosLibrary::Get()->GetInputMethodLibrary()->SetImePropertyActivated(
- key, false);
- }
- return;
- }
-
- LOG(ERROR) << "Unexpected index: " << index;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// LanguageMenuButton, views::ViewMenuDelegate implementation:
-
-void LanguageMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
- UserMetrics::RecordAction(
- UserMetricsAction("LanguageMenuButton_Open"));
- input_method_descriptors_.reset(CrosLibrary::Get()->GetInputMethodLibrary()->
- GetActiveInputMethods());
- RebuildModel();
- language_menu_.Rebuild();
-
- // Disallow the menu widget to grab the keyboard focus. This is necessary to
- // enable users to change status of an input method (e.g. change the input
- // mode from Japanese Hiragana to Japanese Katakana) without discarding a
- // preedit string. See crosbug.com/5796 for details. Note that menus other
- // than this one should not call the Gtk+ API since it is a special API only
- // for a menu related to IME/keyboard. See the Gtk+ API reference at:
- // http://library.gnome.org/devel/gtk/stable/GtkMenuShell.html
- gfx::NativeMenu native_menu = language_menu_.GetNativeMenu();
- if (native_menu) {
- gtk_menu_shell_set_take_focus(GTK_MENU_SHELL(native_menu), FALSE);
- } else {
- LOG(ERROR)
- << "Can't call gtk_menu_shell_set_take_focus since NativeMenu is NULL";
- }
-
- language_menu_.UpdateStates();
- language_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// InputMethodLibrary::Observer implementation:
-
-void LanguageMenuButton::InputMethodChanged(InputMethodLibrary* obj) {
- UserMetrics::RecordAction(
- UserMetricsAction("LanguageMenuButton_InputMethodChanged"));
-
- const InputMethodDescriptor& previous_input_method =
- obj->previous_input_method();
- const InputMethodDescriptor& current_input_method =
- obj->current_input_method();
- UpdateIndicatorFromInputMethod(current_input_method);
- // Update Chrome prefs as well.
- if (host_->IsBrowserMode()) {
- if (GetPrefService(host_)) { // make sure we're not in unit tests.
- // Sometimes (e.g. initial boot) |previous_input_method.id| is empty.
- previous_input_method_pref_.SetValue(previous_input_method.id);
- current_input_method_pref_.SetValue(current_input_method.id);
- }
- } else {
- // We're in the login screen (i.e. not in the normal browser mode nor screen
- // locker mode). If a user has already logged in, we should not update the
- // local state since a profile for the user might be loaded before the
- // buttun for the login screen is destroyed.
- if (!logged_in_ && g_browser_process && g_browser_process->local_state()) {
- g_browser_process->local_state()->SetString(
- language_prefs::kPreferredKeyboardLayout, current_input_method.id);
- g_browser_process->local_state()->SavePersistentPrefs();
- }
- }
-}
-
-void LanguageMenuButton::ActiveInputMethodsChanged(InputMethodLibrary* obj) {
- // Update the icon if active input methods are changed. See also
- // comments in UpdateIndicator()
- UpdateIndicatorFromInputMethod(obj->current_input_method());
-}
-
-void LanguageMenuButton::ImePropertiesChanged(InputMethodLibrary* obj) {
+ LanguageMenuButton::UpdateUI(L"US", L"");
}
////////////////////////////////////////////////////////////////////////////////
@@ -460,12 +61,15 @@ void LanguageMenuButton::OnLocaleChanged() {
input_method::OnLocaleChanged();
const InputMethodDescriptor& input_method =
CrosLibrary::Get()->GetInputMethodLibrary()->current_input_method();
- UpdateIndicatorFromInputMethod(input_method);
+ UpdateUIFromInputMethod(input_method);
Layout();
SchedulePaint();
}
-void LanguageMenuButton::UpdateIndicator(
+////////////////////////////////////////////////////////////////////////////////
+// InputMethodMenu::InputMethodMenuHost implementation:
+
+void LanguageMenuButton::UpdateUI(
const std::wstring& name, const std::wstring& tooltip) {
// Hide the button only if there is only one input method, and the input
// method is a XKB keyboard layout. We don't hide the button for other
@@ -488,184 +92,12 @@ void LanguageMenuButton::UpdateIndicator(
SchedulePaint();
}
-void LanguageMenuButton::UpdateIndicatorFromInputMethod(
- const InputMethodDescriptor& input_method) {
- const std::wstring name = GetTextForIndicator(input_method);
- const std::wstring tooltip = GetTextForMenu(input_method);
- UpdateIndicator(name, tooltip);
-}
-
-void LanguageMenuButton::RebuildModel() {
- model_.reset(new menus::SimpleMenuModel(NULL));
- string16 dummy_label = UTF8ToUTF16("");
- // Indicates if separator's needed before each section.
- bool need_separator = false;
-
- if (!input_method_descriptors_->empty()) {
- // We "abuse" the command_id and group_id arguments of AddRadioItem method.
- // A COMMAND_ID_XXX enum value is passed as command_id, and array index of
- // |input_method_descriptors_| or |property_list| is passed as group_id.
- for (size_t i = 0; i < input_method_descriptors_->size(); ++i) {
- model_->AddRadioItem(COMMAND_ID_INPUT_METHODS, dummy_label, i);
- }
-
- need_separator = true;
- }
-
- const ImePropertyList& property_list
- = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
- if (!property_list.empty()) {
- if (need_separator)
- model_->AddSeparator();
- for (size_t i = 0; i < property_list.size(); ++i) {
- model_->AddRadioItem(COMMAND_ID_IME_PROPERTIES, dummy_label, i);
- }
- need_separator = true;
- }
-
- if (host_->ShouldOpenButtonOptions(this)) {
- // Note: We use AddSeparator() for separators, and AddRadioItem() for all
- // other items even if an item is not actually a radio item.
- if (need_separator)
- model_->AddSeparator();
- model_->AddRadioItem(COMMAND_ID_CUSTOMIZE_LANGUAGE, dummy_label,
- 0 /* dummy */);
- }
-}
-
-bool LanguageMenuButton::IndexIsInInputMethodList(int index) const {
- DCHECK_GE(index, 0);
- DCHECK(model_.get());
- if (index >= model_->GetItemCount()) {
- return false;
- }
-
- return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
- (model_->GetCommandIdAt(index) == COMMAND_ID_INPUT_METHODS) &&
- input_method_descriptors_.get() &&
- (index < static_cast<int>(input_method_descriptors_->size())));
-}
-
-bool LanguageMenuButton::GetPropertyIndex(
- int index, int* property_index) const {
- DCHECK_GE(index, 0);
- DCHECK(property_index);
- DCHECK(model_.get());
- if (index >= model_->GetItemCount()) {
- return false;
- }
-
- if ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
- (model_->GetCommandIdAt(index) == COMMAND_ID_IME_PROPERTIES)) {
- const int tmp_property_index = model_->GetGroupIdAt(index);
- const ImePropertyList& property_list
- = CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
- if (tmp_property_index < static_cast<int>(property_list.size())) {
- *property_index = tmp_property_index;
- return true;
- }
- }
- return false;
-}
-
-bool LanguageMenuButton::IndexPointsToConfigureImeMenuItem(int index) const {
- DCHECK_GE(index, 0);
- DCHECK(model_.get());
- if (index >= model_->GetItemCount()) {
- return false;
- }
-
- return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
- (model_->GetCommandIdAt(index) == COMMAND_ID_CUSTOMIZE_LANGUAGE));
-}
-
-std::wstring LanguageMenuButton::GetTextForIndicator(
- const InputMethodDescriptor& input_method) {
- // For the status area, we use two-letter, upper-case language code like
- // "US" and "JP".
- std::wstring text;
-
- // Check special cases first.
- for (size_t i = 0; i < kMappingFromIdToIndicatorTextLen; ++i) {
- if (kMappingFromIdToIndicatorText[i].input_method_id == input_method.id) {
- text = UTF8ToWide(kMappingFromIdToIndicatorText[i].indicator_text);
- break;
- }
- }
-
- // Display the keyboard layout name when using ibus-xkb.
- if (text.empty()) {
- const size_t kMaxKeyboardLayoutNameLen = 2;
- const std::wstring keyboard_layout = UTF8ToWide(
- input_method::GetKeyboardLayoutName(input_method.id));
- text = StringToUpperASCII(keyboard_layout).substr(
- 0, kMaxKeyboardLayoutNameLen);
- }
-
- // TODO(yusukes): Some languages have two or more input methods. For example,
- // Thai has 3, Vietnamese has 4. If these input methods could be activated at
- // the same time, we should do either of the following:
- // (1) Add mappings to |kMappingFromIdToIndicatorText|
- // (2) Add suffix (1, 2, ...) to |text| when ambiguous.
-
- if (text.empty()) {
- const size_t kMaxLanguageNameLen = 2;
- std::string language_code =
- input_method::GetLanguageCodeFromDescriptor(input_method);
-
- // Use "CN" for simplified Chinese and "TW" for traditonal Chinese,
- // rather than "ZH".
- if (StartsWithASCII(language_code, "zh-", false)) {
- std::vector<std::string> portions;
- SplitString(language_code, '-', &portions);
- if (portions.size() >= 2 && !portions[1].empty()) {
- language_code = portions[1];
- }
- }
-
- text = StringToUpperASCII(UTF8ToWide(language_code)).substr(
- 0, kMaxLanguageNameLen);
- }
- DCHECK(!text.empty());
- return text;
-}
-
-std::wstring LanguageMenuButton::GetTextForMenu(
- const InputMethodDescriptor& input_method) {
- // We don't show language here. Name of keyboard layout or input method
- // usually imply (or explicitly include) its language.
-
- // Special case for Dutch, French and German: these languages have multiple
- // keyboard layouts and share the same laout of keyboard (Belgian). We need to
- // show explicitly the language for the layout.
- // For Arabic and Hindi: they share "Standard Input Method".
- const std::string language_code
- = input_method::GetLanguageCodeFromDescriptor(input_method);
- std::wstring text;
- if (language_code == "ar" ||
- language_code == "hi" ||
- language_code == "nl" ||
- language_code == "fr" ||
- language_code == "de") {
- text = GetLanguageName(language_code) + L" - ";
- }
- text += input_method::GetString(input_method.display_name);
-
- DCHECK(!text.empty());
- return text;
-}
-
-void LanguageMenuButton::RegisterPrefs(PrefService* local_state) {
- local_state->RegisterStringPref(language_prefs::kPreferredKeyboardLayout,
- "");
+void LanguageMenuButton::OpenConfigUI() {
+ host_->OpenButtonOptions(this); // ask browser to open the DOMUI page.
}
-void LanguageMenuButton::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::LOGIN_USER_CHANGED) {
- logged_in_ = true;
- }
+bool LanguageMenuButton::ShouldSupportConfigUI() {
+ return host_->ShouldOpenButtonOptions(this);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/status/language_menu_button.h b/chrome/browser/chromeos/status/language_menu_button.h
index 7610e8c..28a21b5 100644
--- a/chrome/browser/chromeos/status/language_menu_button.h
+++ b/chrome/browser/chromeos/status/language_menu_button.h
@@ -6,125 +6,35 @@
#define CHROME_BROWSER_CHROMEOS_STATUS_LANGUAGE_MENU_BUTTON_H_
#pragma once
-#include "app/menus/simple_menu_model.h"
-#include "chrome/browser/chromeos/cros/input_method_library.h"
-#include "chrome/browser/chromeos/status/status_area_button.h"
-#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
-#include "views/controls/menu/menu_2.h"
-#include "views/controls/menu/view_menu_delegate.h"
+#include <string>
-class SkBitmap;
+#include "chrome/browser/chromeos/status/input_method_menu.h"
+#include "chrome/browser/chromeos/status/status_area_button.h"
namespace chromeos {
class StatusAreaHost;
-// The language menu button in the status area.
-// This class will handle getting the IME/XKB status and populating the menu.
+// A class for the button in the status area which expands the dropdown menu for
+// switching input method and keyboard layout.
class LanguageMenuButton : public StatusAreaButton,
- public views::ViewMenuDelegate,
- public menus::MenuModel,
- public InputMethodLibrary::Observer,
- public NotificationObserver {
+ public InputMethodMenu {
public:
explicit LanguageMenuButton(StatusAreaHost* host);
- virtual ~LanguageMenuButton();
-
- // menus::MenuModel implementation.
- virtual bool HasIcons() const;
- virtual int GetItemCount() const;
- virtual menus::MenuModel::ItemType GetTypeAt(int index) const;
- virtual int GetCommandIdAt(int index) const;
- virtual string16 GetLabelAt(int index) const;
- virtual bool IsLabelDynamicAt(int index) const;
- virtual bool GetAcceleratorAt(int index,
- menus::Accelerator* accelerator) const;
- virtual bool IsItemCheckedAt(int index) const;
- virtual int GetGroupIdAt(int index) const;
- virtual bool GetIconAt(int index, SkBitmap* icon) const;
- virtual menus::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const;
- virtual bool IsEnabledAt(int index) const;
- virtual menus::MenuModel* GetSubmenuModelAt(int index) const;
- virtual void HighlightChangedTo(int index);
- virtual void ActivatedAt(int index);
- virtual void MenuWillShow();
-
- // InputMethodLibrary::Observer implementation.
- virtual void InputMethodChanged(InputMethodLibrary* obj);
- virtual void ImePropertiesChanged(InputMethodLibrary* obj);
- virtual void ActiveInputMethodsChanged(InputMethodLibrary* obj);
-
- // NotificationObserver implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual ~LanguageMenuButton() {}
- // Converts an InputMethodDescriptor object into human readable string.
- // Returns a text for the indicator on top right corner of the Chrome window.
- static std::wstring GetTextForIndicator(
- const InputMethodDescriptor& input_method);
-
- // Converts an InputMethodDescriptor object into human readable string.
- // Returns a string for the drop-down menu and the tooltip for the indicator.
- static std::wstring GetTextForMenu(const InputMethodDescriptor& input_method);
-
- // Registers input method preferences for the login screen.
- static void RegisterPrefs(PrefService* local_state);
-
- protected:
// views::View implementation.
virtual void OnLocaleChanged();
private:
- // views::ViewMenuDelegate implementation.
- virtual void RunMenu(views::View* source, const gfx::Point& pt);
-
- // Updates the status area with |name| and tooltip with |tooltip|.
- void UpdateIndicator(const std::wstring& name, const std::wstring& tooltip);
-
- // Updates the status area from the given input method.
- void UpdateIndicatorFromInputMethod(
- const InputMethodDescriptor& input_method);
-
- // Rebuilds |model_|. This function should be called whenever
- // |input_method_descriptors_| is updated, or ImePropertiesChanged() is
- // called.
- void RebuildModel();
-
- // Returns true if the zero-origin |index| points to one of the input methods.
- bool IndexIsInInputMethodList(int index) const;
-
- // Returns true if the zero-origin |index| points to one of the IME
- // properties. When returning true, |property_index| is updated so that
- // property_list.at(property_index) points to the menu item.
- bool GetPropertyIndex(int index, int* property_index) const;
-
- // Returns true if the zero-origin |index| points to the "Configure IME" menu
- // item.
- bool IndexPointsToConfigureImeMenuItem(int index) const;
-
- // The current input method list.
- scoped_ptr<InputMethodDescriptors> input_method_descriptors_;
-
- // Objects for reading/writing the Chrome prefs.
- StringPrefMember previous_input_method_pref_;
- StringPrefMember current_input_method_pref_;
-
- // We borrow menus::SimpleMenuModel implementation to maintain the current
- // content of the pop-up menu. The menus::MenuModel is implemented using this
- // |model_|.
- scoped_ptr<menus::SimpleMenuModel> model_;
-
- // The language menu which pops up when the button in status area is clicked.
- views::Menu2 language_menu_;
+ // InputMethodMenu implementation.
+ virtual void UpdateUI(
+ const std::wstring& name, const std::wstring& tooltip);
+ virtual bool ShouldSupportConfigUI();
+ virtual void OpenConfigUI();
+ private:
StatusAreaHost* host_;
- NotificationRegistrar registrar_;
- bool logged_in_;
DISALLOW_COPY_AND_ASSIGN(LanguageMenuButton);
};