summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryusukes@google.com <yusukes@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-20 04:11:25 +0000
committeryusukes@google.com <yusukes@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-20 04:11:25 +0000
commit269cba58576443c84e9e6134da52fe66dd3d9164 (patch)
tree3be568a45ba91d34ac3729d7fb0322af44b219ad
parent2dccf1b6351bbcdbea1a81a2563f1a5840a29507 (diff)
downloadchromium_src-269cba58576443c84e9e6134da52fe66dd3d9164.zip
chromium_src-269cba58576443c84e9e6134da52fe66dd3d9164.tar.gz
chromium_src-269cba58576443c84e9e6134da52fe66dd3d9164.tar.bz2
Support intra-IME switcing (e.g. "Japanese Hiragana mode" to "Japanese HalfWidthKatakana mode").
Displays IME properties on the language menu. BUG=none TEST=manual Review URL: http://codereview.chromium.org/517064 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36607 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/language_library.cc89
-rw-r--r--chrome/browser/chromeos/language_library.h32
-rw-r--r--chrome/browser/chromeos/language_menu_button.cc242
-rw-r--r--chrome/browser/chromeos/language_menu_button.h28
4 files changed, 346 insertions, 45 deletions
diff --git a/chrome/browser/chromeos/language_library.cc b/chrome/browser/chromeos/language_library.cc
index fcb0604..4d8899c 100644
--- a/chrome/browser/chromeos/language_library.cc
+++ b/chrome/browser/chromeos/language_library.cc
@@ -17,6 +17,28 @@ struct RunnableMethodTraits<chromeos::LanguageLibrary> {
void ReleaseCallee(chromeos::LanguageLibrary* obj) {}
};
+namespace {
+
+// Finds a property which has |new_prop.key| from |prop_list|, and replaces the
+// property with |new_prop|. Returns true if such a property is found.
+bool FindAndUpdateProperty(const chromeos::ImeProperty& new_prop,
+ chromeos::ImePropertyList* prop_list) {
+ for (size_t i = 0; i < prop_list->size(); ++i) {
+ chromeos::ImeProperty& prop = prop_list->at(i);
+ if (prop.key == new_prop.key) {
+ const int saved_id = prop.selection_item_id;
+ // Update the list except the radio id. As written in chromeos_language.h,
+ // |prop.selection_item_id| is dummy.
+ prop = new_prop;
+ prop.selection_item_id = saved_id;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
namespace chromeos {
LanguageLibrary::LanguageLibrary() : language_status_connection_(NULL) {
@@ -75,6 +97,22 @@ void LanguageLibrary::ChangeLanguage(
}
}
+void LanguageLibrary::ActivateImeProperty(const std::string& key) {
+ DCHECK(!key.empty());
+ if (EnsureLoaded()) {
+ chromeos::ActivateImeProperty(
+ language_status_connection_, key.c_str());
+ }
+}
+
+void LanguageLibrary::DeactivateImeProperty(const std::string& key) {
+ DCHECK(!key.empty());
+ if (EnsureLoaded()) {
+ chromeos::DeactivateImeProperty(
+ language_status_connection_, key.c_str());
+ }
+}
+
bool LanguageLibrary::ActivateLanguage(
LanguageCategory category, const std::string& id) {
bool success = false;
@@ -102,9 +140,27 @@ void LanguageLibrary::LanguageChangedHandler(
language_library->UpdateCurrentLanguage(current_language);
}
+// static
+void LanguageLibrary::RegisterPropertiesHandler(
+ void* object, const ImePropertyList& prop_list) {
+ LanguageLibrary* language_library = static_cast<LanguageLibrary*>(object);
+ language_library->RegisterProperties(prop_list);
+}
+
+// static
+void LanguageLibrary::UpdatePropertyHandler(
+ void* object, const ImePropertyList& prop_list) {
+ LanguageLibrary* language_library = static_cast<LanguageLibrary*>(object);
+ language_library->UpdateProperty(prop_list);
+}
+
void LanguageLibrary::Init() {
- language_status_connection_ = chromeos::MonitorLanguageStatus(
- &LanguageChangedHandler, this);
+ chromeos::LanguageStatusMonitorFunctions monitor_functions;
+ monitor_functions.current_language = &LanguageChangedHandler;
+ monitor_functions.register_ime_properties = &RegisterPropertiesHandler;
+ monitor_functions.update_ime_property = &UpdatePropertyHandler;
+ language_status_connection_
+ = chromeos::MonitorLanguageStatus(monitor_functions, this);
}
void LanguageLibrary::UpdateCurrentLanguage(
@@ -125,4 +181,33 @@ void LanguageLibrary::UpdateCurrentLanguage(
FOR_EACH_OBSERVER(Observer, observers_, LanguageChanged(this));
}
+void LanguageLibrary::RegisterProperties(const ImePropertyList& prop_list) {
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &LanguageLibrary::RegisterProperties, prop_list));
+ return;
+ }
+
+ // |prop_list| might be empty. This means "clear all properties."
+ current_ime_properties_ = prop_list;
+ FOR_EACH_OBSERVER(Observer, observers_, ImePropertiesChanged(this));
+}
+
+void LanguageLibrary::UpdateProperty(const ImePropertyList& prop_list) {
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &LanguageLibrary::UpdateProperty, prop_list));
+ return;
+ }
+
+ for (size_t i = 0; i < prop_list.size(); ++i) {
+ FindAndUpdateProperty(prop_list[i], &current_ime_properties_);
+ }
+ FOR_EACH_OBSERVER(Observer, observers_, ImePropertiesChanged(this));
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/language_library.h b/chrome/browser/chromeos/language_library.h
index 88c197c..f19c989 100644
--- a/chrome/browser/chromeos/language_library.h
+++ b/chrome/browser/chromeos/language_library.h
@@ -23,6 +23,7 @@ class LanguageLibrary {
public:
virtual ~Observer() = 0;
virtual void LanguageChanged(LanguageLibrary* obj) = 0;
+ virtual void ImePropertiesChanged(LanguageLibrary* obj) = 0;
};
// This gets the singleton LanguageLibrary
@@ -54,6 +55,14 @@ class LanguageLibrary {
// in src third_party/cros/ for details.
void ChangeLanguage(LanguageCategory category, const std::string& id);
+ // Activates an IME property identified by |key|. Examples of keys are:
+ // "InputMode.Katakana", "InputMode.HalfWidthKatakana", "TypingMode.Romaji",
+ // and "TypingMode.Kana."
+ void ActivateImeProperty(const std::string& key);
+
+ // Deactivates an IME property identified by |key|.
+ void DeactivateImeProperty(const std::string& key);
+
// Activates the language specified by |category| and |id|. Returns true
// on success.
bool ActivateLanguage(LanguageCategory category, const std::string& id);
@@ -66,6 +75,10 @@ class LanguageLibrary {
return current_language_;
}
+ const ImePropertyList& current_ime_properties() const {
+ return current_ime_properties_;
+ }
+
private:
friend struct DefaultSingletonTraits<LanguageLibrary>;
@@ -73,10 +86,17 @@ class LanguageLibrary {
~LanguageLibrary();
// This method is called when there's a change in language status.
- // This method is called on a background thread.
static void LanguageChangedHandler(
void* object, const InputLanguage& current_language);
+ // This method is called when an IME engine sends "RegisterProperties" signal.
+ static void RegisterPropertiesHandler(
+ void* object, const ImePropertyList& prop_list);
+
+ // This method is called when an IME engine sends "UpdateProperty" signal.
+ static void UpdatePropertyHandler(
+ void* object, const ImePropertyList& prop_list);
+
// This methods starts the monitoring of language changes.
void Init();
@@ -84,6 +104,12 @@ class LanguageLibrary {
// This will notify all the Observers.
void UpdateCurrentLanguage(const InputLanguage& current_language);
+ // Called by the handler to register IME properties.
+ void RegisterProperties(const ImePropertyList& prop_list);
+
+ // Called by the handler to update IME properties.
+ void UpdateProperty(const ImePropertyList& prop_list);
+
// A reference to the language api, to allow callbacks when the language
// status changes.
LanguageStatusConnection* language_status_connection_;
@@ -92,6 +118,10 @@ class LanguageLibrary {
// The language (IME or XKB layout) which currently selected.
InputLanguage current_language_;
+ // The IME properties which the current IME engine uses. The list might be
+ // empty when no IME is used.
+ ImePropertyList current_ime_properties_;
+
DISALLOW_COPY_AND_ASSIGN(LanguageLibrary);
};
diff --git a/chrome/browser/chromeos/language_menu_button.cc b/chrome/browser/chromeos/language_menu_button.cc
index 87092cc..38bad35 100644
--- a/chrome/browser/chromeos/language_menu_button.cc
+++ b/chrome/browser/chromeos/language_menu_button.cc
@@ -13,26 +13,59 @@
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
+// The language menu consists of 3 parts (in this order):
+//
+// (1) XKB layout names and IME languages names. The size of the list is
+// always >= 1.
+// (2) IME properties. This list might be empty.
+// (3) "Configure IME..." button.
+//
+// Example of the menu (Japanese):
+//
+// ============================== (border of the popup window)
+// [ ] US (|index| in the following functions is 0)
+// [*] Anthy
+// [ ] PinYin
+// ------------------------------ (separator)
+// [*] Hiragana (index = 5, The property has 2 radio groups)
+// [ ] Katakana
+// [ ] HalfWidthKatakana
+// [*] Roman
+// [ ] Kana
+// ------------------------------ (separator)
+// Configure IME... (index = 11)
+// ============================== (border of the popup window)
+//
+// Example of the menu (Simplified Chinese):
+//
+// ============================== (border of the popup window)
+// [ ] US
+// [ ] Anthy
+// [*] PinYin
+// ------------------------------ (separator)
+// Switch to full letter mode (The property has 2 command buttons)
+// Switch to half punctuation mode
+// ------------------------------ (separator)
+// Configure IME...
+// ============================== (border of the popup window)
+//
+
namespace {
-const int kRadioGroupNone = 0;
-const int kRadioGroupLanguage = 1;
+// Constants to specify the type of items in |model_|.
+enum {
+ COMMAND_ID_LANGUAGES = 0, // US, Anthy, PinYin, ...
+ COMMAND_ID_IME_PROPERTIES, // Hiragana, Katakana, ...
+ COMMAND_ID_CONFIGURE_IME, // The "Configure IME..." button.
+};
+
+// A group ID for IME properties starts from 0. We use the huge value for the
+// XKB/IME language list to avoid conflict.
+const int kRadioGroupLanguage = 1 << 16;
+const int kRadioGroupNone = -1;
const size_t kMaxLanguageNameLen = 7;
const wchar_t kSpacer[] = L"MMMMMMM";
-// Returns true if the |index| points to the "Configure IME" menu item.
-bool IsIndexShowControlPanel(
- int index, chromeos::InputLanguageList* language_list) {
- DCHECK_GE(index, 0);
- if (language_list->empty()) {
- // If language_list is empty, then there's no separator. So "Configure IME"
- // should be at index 0.
- DCHECK_EQ(index, 0);
- return index == 0;
- }
- return static_cast<size_t>(index) == (language_list->size() + 1);
-}
-
// Converts chromeos::InputLanguage object into human readable string. Returns
// a string for the drop-down menu if |for_menu| is true. Otherwise, returns a
// string for the status area.
@@ -73,11 +106,15 @@ namespace chromeos {
LanguageMenuButton::LanguageMenuButton(Browser* browser)
: MenuButton(NULL, std::wstring(), this, false),
language_list_(LanguageLibrary::Get()->GetLanguages()),
- // Since the constructor of |language_menu_| calls this->GetItemCount(),
- // we have to initialize |language_list_| before hand.
+ 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)),
browser_(browser) {
DCHECK(language_list_.get() && !language_list_->empty());
+ // Update the model
+ RebuildModel();
// Grab the real estate.
UpdateIcon(kSpacer);
// Display the default XKB name (usually "US").
@@ -94,7 +131,7 @@ LanguageMenuButton::~LanguageMenuButton() {
// LanguageMenuButton, menus::MenuModel implementation:
int LanguageMenuButton::GetCommandIdAt(int index) const {
- return index; // dummy
+ return 0; // dummy
}
bool LanguageMenuButton::IsLabelDynamicAt(int index) const {
@@ -111,19 +148,35 @@ bool LanguageMenuButton::GetAcceleratorAt(
bool LanguageMenuButton::IsItemCheckedAt(int index) const {
DCHECK_GE(index, 0);
DCHECK(language_list_.get());
- if (static_cast<size_t>(index) < language_list_->size()) {
+
+ if (IndexIsInLanguageList(index)) {
const InputLanguage& language = language_list_->at(index);
return language == LanguageLibrary::Get()->current_language();
}
+
+ if (GetPropertyIndex(index, &index)) {
+ const ImePropertyList& property_list
+ = LanguageLibrary::Get()->current_ime_properties();
+ return property_list.at(index).is_selection_item_checked;
+ }
+
+ // Separator(s) or the "Configure IME" button.
return false;
}
int LanguageMenuButton::GetGroupIdAt(int index) const {
DCHECK_GE(index, 0);
- DCHECK(language_list_.get());
- if (static_cast<size_t>(index) < language_list_->size()) {
+
+ if (IndexIsInLanguageList(index)) {
return kRadioGroupLanguage;
}
+
+ if (GetPropertyIndex(index, &index)) {
+ const ImePropertyList& property_list
+ = LanguageLibrary::Get()->current_ime_properties();
+ return property_list.at(index).selection_item_id;
+ }
+
return kRadioGroupNone;
}
@@ -133,15 +186,18 @@ bool LanguageMenuButton::HasIcons() const {
}
bool LanguageMenuButton::GetIconAt(int index, SkBitmap* icon) const {
+ // TODO(yusukes): Display IME icons.
return false;
}
bool LanguageMenuButton::IsEnabledAt(int index) const {
- // Just return true so all IMEs and XLB layouts listed could be clicked.
+ // Just return true so all IMEs, XKB layouts, and IME properties could be
+ // clicked.
return true;
}
menus::MenuModel* LanguageMenuButton::GetSubmenuModelAt(int index) const {
+ // We don't use nested menus.
return NULL;
}
@@ -154,54 +210,100 @@ void LanguageMenuButton::MenuWillShow() {
}
int LanguageMenuButton::GetItemCount() const {
- DCHECK(language_list_.get());
- if (language_list_->empty()) {
- return 1; // no separator; "Configure IME" only
+ if (!model_.get()) {
+ // Model is not constructed yet. This means that LanguageMenuButton is
+ // being constructed. Return zero.
+ return 0;
}
- return language_list_->size() + 2; // separator + "Configure IME"
+ return model_->GetItemCount();
}
menus::MenuModel::ItemType LanguageMenuButton::GetTypeAt(int index) const {
DCHECK_GE(index, 0);
- DCHECK(language_list_.get());
- if (IsIndexShowControlPanel(index, language_list_.get())) {
+
+ if (IndexPointsToConfigureImeMenuItem(index)) {
return menus::MenuModel::TYPE_COMMAND; // "Configure IME"
}
- if (static_cast<size_t>(index) < language_list_->size()) {
+
+ if (IndexIsInLanguageList(index)) {
return menus::MenuModel::TYPE_RADIO;
}
- DCHECK_EQ(static_cast<size_t>(index), language_list_->size());
+ if (GetPropertyIndex(index, &index)) {
+ const ImePropertyList& property_list
+ = LanguageLibrary::Get()->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(language_list_.get());
- if (IsIndexShowControlPanel(index, language_list_.get())) {
+
+ if (IndexPointsToConfigureImeMenuItem(index)) {
// TODO(yusukes): Use message catalog.
return WideToUTF16(L"Configure IME...");
}
- if (static_cast<size_t>(index) < language_list_->size()) {
- std::string name = FormatInputLanguage(language_list_->at(index), true);
- return UTF8ToUTF16(name);
+
+ std::string name;
+ if (IndexIsInLanguageList(index)) {
+ name = FormatInputLanguage(language_list_->at(index), true);
+ } else if (GetPropertyIndex(index, &index)) {
+ const ImePropertyList& property_list
+ = LanguageLibrary::Get()->current_ime_properties();
+ name = property_list.at(index).label;
}
- NOTREACHED();
- return WideToUTF16(L"");
+
+ return UTF8ToUTF16(name);
}
void LanguageMenuButton::ActivatedAt(int index) {
DCHECK_GE(index, 0);
DCHECK(language_list_.get());
- if (IsIndexShowControlPanel(index, language_list_.get())) {
+
+ if (IndexPointsToConfigureImeMenuItem(index)) {
browser_->ShowControlPanel();
return;
}
- if (static_cast<size_t>(index) < language_list_->size()) {
+
+ if (IndexIsInLanguageList(index)) {
+ // Inter-IME switching or IME-XKB switching.
const InputLanguage& language = language_list_->at(index);
LanguageLibrary::Get()->ChangeLanguage(language.category, language.id);
return;
}
+
+ if (GetPropertyIndex(index, &index)) {
+ // Intra-IME switching (e.g. Japanese-Hiragana to Japanese-Katakana).
+ const ImePropertyList& property_list
+ = LanguageLibrary::Get()->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) {
+ LanguageLibrary::Get()->DeactivateImeProperty(
+ property_list.at(i).key);
+ }
+ }
+ // Then, activate the property clicked.
+ LanguageLibrary::Get()->ActivateImeProperty(key);
+ } else {
+ // Command button like "Switch to half punctuation mode" is clicked.
+ // We can always use "Deactivate" for command buttons.
+ LanguageLibrary::Get()->DeactivateImeProperty(key);
+ }
+ return;
+ }
+
+ // Separators are not clickable.
NOTREACHED();
}
@@ -210,19 +312,24 @@ void LanguageMenuButton::ActivatedAt(int index) {
void LanguageMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
language_list_.reset(LanguageLibrary::Get()->GetLanguages());
+ RebuildModel();
language_menu_.Rebuild();
language_menu_.UpdateStates();
language_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
}
////////////////////////////////////////////////////////////////////////////////
-// LanguageMenuButton, PowerLibrary::Observer implementation:
+// LanguageLibrary::Observer implementation:
void LanguageMenuButton::LanguageChanged(LanguageLibrary* obj) {
const std::string name = FormatInputLanguage(obj->current_language(), false);
UpdateIcon(UTF8ToWide(name));
}
+void LanguageMenuButton::ImePropertiesChanged(LanguageLibrary* obj) {
+ RebuildModel();
+}
+
void LanguageMenuButton::UpdateIcon(const std::wstring& name) {
set_border(NULL);
SetFont(ResourceBundle::GetSharedInstance().GetFont(
@@ -235,7 +342,62 @@ void LanguageMenuButton::UpdateIcon(const std::wstring& name) {
SchedulePaint();
}
+void LanguageMenuButton::RebuildModel() {
+ model_.reset(new menus::SimpleMenuModel(NULL));
+ string16 dummy_label = UTF8ToUTF16("");
+
+ // 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
+ // |language_list_| or |property_list| is passed as group_id.
+ for (size_t i = 0; i < language_list_->size(); ++i) {
+ model_->AddRadioItem(COMMAND_ID_LANGUAGES, dummy_label, i);
+ }
+ model_->AddSeparator();
+
+ const ImePropertyList& property_list
+ = LanguageLibrary::Get()->current_ime_properties();
+ for (size_t i = 0; i < property_list.size(); ++i) {
+ model_->AddRadioItem(COMMAND_ID_IME_PROPERTIES, dummy_label, i);
+ }
+ if (!property_list.empty()) {
+ model_->AddSeparator();
+ }
+
+ // Note: We use AddSeparator() for separators, and AddRadioItem() for all
+ // other items even if an item is not actually a radio item.
+ model_->AddRadioItem(COMMAND_ID_CONFIGURE_IME, dummy_label, 0 /* dummy */);
+}
+
+bool LanguageMenuButton::IndexIsInLanguageList(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(model_.get());
+
+ return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
+ (model_->GetCommandIdAt(index) == COMMAND_ID_LANGUAGES));
+}
+
+bool LanguageMenuButton::GetPropertyIndex(
+ int index, int* property_index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(property_index);
+ DCHECK(model_.get());
+
+ if ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
+ (model_->GetCommandIdAt(index) == COMMAND_ID_IME_PROPERTIES)) {
+ *property_index = model_->GetGroupIdAt(index);
+ return true;
+ }
+ return false;
+}
+
+bool LanguageMenuButton::IndexPointsToConfigureImeMenuItem(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(model_.get());
+
+ return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
+ (model_->GetCommandIdAt(index) == COMMAND_ID_CONFIGURE_IME));
+}
+
// TODO(yusukes): Register and handle hotkeys for IME and XKB switching?
} // namespace chromeos
-
diff --git a/chrome/browser/chromeos/language_menu_button.h b/chrome/browser/chromeos/language_menu_button.h
index f1ebfbc..6d74a48 100644
--- a/chrome/browser/chromeos/language_menu_button.h
+++ b/chrome/browser/chromeos/language_menu_button.h
@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LANGUAGE_MENU_BUTTON_H_
#define CHROME_BROWSER_CHROMEOS_LANGUAGE_MENU_BUTTON_H_
+#include "app/menus/simple_menu_model.h"
#include "chrome/browser/chromeos/language_library.h"
#include "chrome/browser/chromeos/status_area_button.h"
#include "views/controls/menu/menu_2.h"
@@ -25,7 +26,7 @@ class LanguageMenuButton : public views::MenuButton,
explicit LanguageMenuButton(Browser* browser);
virtual ~LanguageMenuButton();
- // views::Menu2Model implementation.
+ // menus::MenuModel implementation.
virtual bool HasIcons() const;
virtual int GetItemCount() const;
virtual menus::MenuModel::ItemType GetTypeAt(int index) const;
@@ -45,6 +46,7 @@ class LanguageMenuButton : public views::MenuButton,
// LanguageLibrary::Observer implementation.
virtual void LanguageChanged(LanguageLibrary* obj);
+ virtual void ImePropertiesChanged(LanguageLibrary* obj);
private:
// views::ViewMenuDelegate implementation.
@@ -53,10 +55,32 @@ class LanguageMenuButton : public views::MenuButton,
// Update the status area with |name|.
void UpdateIcon(const std::wstring& name);
+ // Rebuilds |model_|. This function should be called whenever |language_list_|
+ // is updated, or ImePropertiesChanged() is called.
+ void RebuildModel();
+
+ // Returns true if the zero-origin |index| points to one of the input
+ // languages.
+ bool IndexIsInLanguageList(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 language list.
scoped_ptr<InputLanguageList> language_list_;
- // The language menu.
+ // 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_;
// The browser window that owns us.
Browser* browser_;