summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/menus/button_menu_item_model.cc20
-rw-r--r--app/menus/button_menu_item_model.h9
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.cc6
-rw-r--r--chrome/browser/gtk/gtk_custom_menu.cc8
-rw-r--r--chrome/browser/gtk/gtk_custom_menu_item.cc42
-rw-r--r--chrome/browser/gtk/gtk_custom_menu_item.h13
-rw-r--r--chrome/browser/gtk/menu_gtk.cc120
-rw-r--r--chrome/browser/gtk/menu_gtk.h16
-rw-r--r--chrome/browser/wrench_menu_model.cc10
-rw-r--r--chrome/browser/wrench_menu_model.h7
10 files changed, 193 insertions, 58 deletions
diff --git a/app/menus/button_menu_item_model.cc b/app/menus/button_menu_item_model.cc
index 3e09253..a7fbcde 100644
--- a/app/menus/button_menu_item_model.cc
+++ b/app/menus/button_menu_item_model.cc
@@ -18,6 +18,15 @@ string16 ButtonMenuItemModel::Delegate::GetLabelForCommandId(
return string16();
}
+bool ButtonMenuItemModel::Delegate::IsCommandIdEnabled(int command_id) const {
+ return true;
+}
+
+bool ButtonMenuItemModel::Delegate::DoesCommandIdDismissMenu(
+ int command_id) const {
+ return true;
+}
+
struct ButtonMenuItemModel::Item {
int command_id;
ButtonType type;
@@ -106,10 +115,21 @@ bool ButtonMenuItemModel::IsEnabledAt(int index) const {
return IsCommandIdEnabled(items_[index].command_id);
}
+bool ButtonMenuItemModel::DismissesMenuAt(int index) const {
+ return DoesCommandIdDismissMenu(items_[index].command_id);
+}
+
bool ButtonMenuItemModel::IsCommandIdEnabled(int command_id) const {
if (delegate_)
return delegate_->IsCommandIdEnabled(command_id);
return true;
}
+bool ButtonMenuItemModel::DoesCommandIdDismissMenu(int command_id) const {
+ if (delegate_)
+ return delegate_->DoesCommandIdDismissMenu(command_id);
+ return true;
+}
+
+
} // namespace menus
diff --git a/app/menus/button_menu_item_model.h b/app/menus/button_menu_item_model.h
index 606e286..265359b 100644
--- a/app/menus/button_menu_item_model.h
+++ b/app/menus/button_menu_item_model.h
@@ -31,7 +31,8 @@ class ButtonMenuItemModel {
// Performs the action associated with the specified command id.
virtual void ExecuteCommand(int command_id) = 0;
- virtual bool IsCommandIdEnabled(int command_id) const { return true; }
+ virtual bool IsCommandIdEnabled(int command_id) const;
+ virtual bool DoesCommandIdDismissMenu(int command_id) const;
protected:
virtual ~Delegate() {}
@@ -84,9 +85,15 @@ class ButtonMenuItemModel {
// Returns the enabled state of the button at |index|.
bool IsEnabledAt(int index) const;
+ // Returns whether clicking on the button at |index| dismisses the menu.
+ bool DismissesMenuAt(int index) const;
+
// Returns the enabled state of the command specified by |command_id|.
bool IsCommandIdEnabled(int command_id) const;
+ // Returns whether clicking on |command_id| dismisses the menu.
+ bool DoesCommandIdDismissMenu(int command_id) const;
+
const string16& label() const { return item_label_; }
private:
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc
index 69fdcb6..8da933d 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_toolbar_gtk.cc
@@ -230,6 +230,8 @@ void BrowserToolbarGtk::Init(Profile* profile,
wrench_menu_.reset(new MenuGtk(this, &wrench_menu_model_));
g_signal_connect(wrench_menu_->widget(), "show",
G_CALLBACK(OnWrenchMenuShowThunk), this);
+ registrar_.Add(this, NotificationType::ZOOM_LEVEL_CHANGED,
+ Source<Profile>(browser_->profile()));
if (ShouldOnlyShowLocation()) {
gtk_widget_show(event_box_);
@@ -379,6 +381,10 @@ void BrowserToolbarGtk::Observe(NotificationType type,
UpdateRoundedness();
} else if (type == NotificationType::UPGRADE_RECOMMENDED) {
MaybeShowUpgradeReminder();
+ } else if (type == NotificationType::ZOOM_LEVEL_CHANGED) {
+ // If our zoom level changed, we need to tell the menu to update its state,
+ // since the menu could still be open.
+ wrench_menu_->UpdateMenu();
} else {
NOTREACHED();
}
diff --git a/chrome/browser/gtk/gtk_custom_menu.cc b/chrome/browser/gtk/gtk_custom_menu.cc
index d666091..15eeb5a 100644
--- a/chrome/browser/gtk/gtk_custom_menu.cc
+++ b/chrome/browser/gtk/gtk_custom_menu.cc
@@ -60,7 +60,8 @@ static gboolean gtk_custom_menu_button_press(GtkWidget* widget,
}
// When processing a button event, abort processing if the cursor isn't in a
-// clickable region.
+// clickable region. If it's in a button that doesn't dismiss the menu, fire
+// that event and abort having the normal GtkMenu code run.
static gboolean gtk_custom_menu_button_release(GtkWidget* widget,
GdkEventButton* event) {
GtkWidget* menu_item = gtk_menu_shell_get_item(
@@ -71,6 +72,11 @@ static gboolean gtk_custom_menu_button_release(GtkWidget* widget,
// Stop processing this event. This isn't a clickable region.
return TRUE;
}
+
+ if (gtk_custom_menu_item_try_no_dismiss_command(
+ GTK_CUSTOM_MENU_ITEM(menu_item))) {
+ return TRUE;
+ }
}
return GTK_WIDGET_CLASS(gtk_custom_menu_parent_class)->
diff --git a/chrome/browser/gtk/gtk_custom_menu_item.cc b/chrome/browser/gtk/gtk_custom_menu_item.cc
index 55281c1..a3d62d4 100644
--- a/chrome/browser/gtk/gtk_custom_menu_item.cc
+++ b/chrome/browser/gtk/gtk_custom_menu_item.cc
@@ -9,6 +9,7 @@
enum {
BUTTON_PUSHED,
+ TRY_BUTTON_PUSHED,
LAST_SIGNAL
};
@@ -102,6 +103,16 @@ static void gtk_custom_menu_item_class_init(GtkCustomMenuItemClass* klass) {
NULL, NULL,
gtk_marshal_NONE__INT,
G_TYPE_NONE, 1, GTK_TYPE_INT);
+ // TODO(erg): Change from BOOL__POINTER to BOOLEAN__INTEGER when we get to
+ // use a modern GTK+.
+ custom_menu_item_signals[TRY_BUTTON_PUSHED] =
+ g_signal_new("try-button-pushed",
+ G_OBJECT_CLASS_TYPE(gobject_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ gtk_marshal_BOOL__POINTER,
+ G_TYPE_BOOLEAN, 1, GTK_TYPE_INT);
}
static void gtk_custom_menu_item_finalize(GObject *object) {
@@ -390,3 +401,34 @@ gboolean gtk_custom_menu_item_is_in_clickable_region(
GtkCustomMenuItem* menu_item) {
return menu_item->currently_selected_button != NULL;
}
+
+gboolean gtk_custom_menu_item_try_no_dismiss_command(
+ GtkCustomMenuItem* menu_item) {
+ GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(menu_item);
+ gboolean activated = TRUE;
+
+ // We work with |currently_selected_button| instead of
+ // |previously_selected_button| since we haven't been "deselect"ed yet.
+ gpointer id_ptr = g_object_get_data(
+ G_OBJECT(custom_item->currently_selected_button), "command-id");
+ if (id_ptr != NULL) {
+ int command_id = GPOINTER_TO_INT(id_ptr);
+ g_signal_emit(custom_item, custom_menu_item_signals[TRY_BUTTON_PUSHED], 0,
+ command_id, &activated);
+ }
+
+ return activated;
+}
+
+void gtk_custom_menu_item_foreach_button(GtkCustomMenuItem* menu_item,
+ GtkCallback callback,
+ gpointer callback_data) {
+ // Even though we're filtering |all_widgets| on GTK_IS_BUTTON(), this isn't
+ // equivalent to |button_widgets| because we also want the button-labels.
+ for (GList* i = menu_item->all_widgets; i && GTK_IS_BUTTON(i->data);
+ i = g_list_next(i)) {
+ if (GTK_IS_BUTTON(i->data)) {
+ callback(GTK_WIDGET(i->data), callback_data);
+ }
+ }
+}
diff --git a/chrome/browser/gtk/gtk_custom_menu_item.h b/chrome/browser/gtk/gtk_custom_menu_item.h
index c730342..76e8c9a 100644
--- a/chrome/browser/gtk/gtk_custom_menu_item.h
+++ b/chrome/browser/gtk/gtk_custom_menu_item.h
@@ -123,6 +123,19 @@ void gtk_custom_menu_item_select_item_by_direction(
gboolean gtk_custom_menu_item_is_in_clickable_region(
GtkCustomMenuItem* menu_item);
+// If the button is released while the |currently_selected_button| isn't
+// supposed to dismiss the menu, this signals to our listeners that we want to
+// run this command if it doesn't dismiss the menu. Returns TRUE if we acted
+// on this button click (and should prevent the normal GtkMenu machinery from
+// firing an "activate" signal).
+gboolean gtk_custom_menu_item_try_no_dismiss_command(
+ GtkCustomMenuItem* menu_item);
+
+// Calls |callback| with every button and button-label in the container.
+void gtk_custom_menu_item_foreach_button(GtkCustomMenuItem* menu_item,
+ GtkCallback callback,
+ gpointer callback_data);
+
G_END_DECLS
#endif // CHROME_BROWSER_GTK_GTK_CUSTOM_MENU_ITEM_H_
diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc
index f242450..4d58ae1 100644
--- a/chrome/browser/gtk/menu_gtk.cc
+++ b/chrome/browser/gtk/menu_gtk.cc
@@ -54,49 +54,13 @@ menus::MenuModel* ModelForMenuItem(GtkMenuItem* menu_item) {
g_object_get_data(G_OBJECT(menu_item), "model"));
}
-void OnSubmenuShow(GtkWidget* widget, gpointer user_data) {
- gint index = GPOINTER_TO_INT(user_data);
-
- GtkMenuItem* item =
- GTK_MENU_ITEM(g_list_nth(GTK_MENU_SHELL(widget)->children, index)->data);
- menus::MenuModel* model = ModelForMenuItem(item);
- std::string label =
- ConvertAcceleratorsFromWindowsStyle(
- UTF16ToUTF8(model->GetLabelAt(index)));
-
-#if GTK_CHECK_VERSION(2, 16, 0)
- gtk_menu_item_set_label(item, label.c_str());
-#else
- gtk_label_set_label(GTK_LABEL(GTK_BIN(item)->child), label.c_str());
-#endif
-}
-
-void OnSubmenuShowButtonMenuItem(GtkWidget* widget, GtkButton* button) {
- menus::ButtonMenuItemModel* model =
- reinterpret_cast<menus::ButtonMenuItemModel*>(
- g_object_get_data(G_OBJECT(button), "button-model"));
- int index = GPOINTER_TO_INT(g_object_get_data(
- G_OBJECT(button), "button-model-id"));
-
- if (model->IsLabelDynamicAt(index)) {
- std::string label =
- ConvertAcceleratorsFromWindowsStyle(
- UTF16ToUTF8(model->GetLabelAt(index)));
- gtk_button_set_label(GTK_BUTTON(button), label.c_str());
- }
- gtk_widget_set_sensitive(GTK_WIDGET(button), model->IsEnabledAt(index));
-}
-
void SetupButtonShowHandler(GtkWidget* button,
- GtkWidget* menu,
menus::ButtonMenuItemModel* model,
int index) {
g_object_set_data(G_OBJECT(button), "button-model",
model);
g_object_set_data(G_OBJECT(button), "button-model-id",
GINT_TO_POINTER(index));
- g_signal_connect(menu, "show", G_CALLBACK(OnSubmenuShowButtonMenuItem),
- button);
}
void OnSubmenuShowButtonImage(GtkWidget* widget, GtkButton* button) {
@@ -222,10 +186,11 @@ GtkWidget* MenuGtk::AppendMenuItemToMenu(int index,
GtkWidget* menu_item,
GtkWidget* menu,
bool connect_to_activate) {
+ SetMenuItemID(menu_item, index);
+
// Native menu items do their own thing, so only selectively listen for the
// activate signal.
if (connect_to_activate) {
- SetMenuItemID(menu_item, index);
g_signal_connect(menu_item, "activate",
G_CALLBACK(OnMenuItemActivatedThunk), this);
}
@@ -283,6 +248,10 @@ void MenuGtk::Cancel() {
gtk_menu_popdown(GTK_MENU(menu_));
}
+void MenuGtk::UpdateMenu() {
+ gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this);
+}
+
GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
const SkBitmap& icon) {
GtkWidget* menu_item =
@@ -372,11 +341,6 @@ void MenuGtk::BuildSubmenuFromModel(menus::MenuModel* model, GtkWidget* menu) {
g_object_set_data(G_OBJECT(menu_item), "model", model);
AppendMenuItemToMenu(i, model, menu_item, menu, connect_to_activate);
- if (model->IsLabelDynamicAt(i)) {
- g_signal_connect(menu, "show", G_CALLBACK(OnSubmenuShow),
- GINT_TO_POINTER(i));
- }
-
menu_item = NULL;
}
}
@@ -390,6 +354,8 @@ GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
g_object_set_data(G_OBJECT(menu_item), "button-model", model);
g_signal_connect(menu_item, "button-pushed",
G_CALLBACK(OnMenuButtonPressedThunk), this);
+ g_signal_connect(menu_item, "try-button-pushed",
+ G_CALLBACK(OnMenuTryButtonPressedThunk), this);
GtkSizeGroup* group = NULL;
for (int i = 0; i < model->GetItemCount(); ++i) {
@@ -415,7 +381,7 @@ GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
UTF16ToUTF8(model->GetLabelAt(i))).c_str());
}
- SetupButtonShowHandler(button, menu, model, i);
+ SetupButtonShowHandler(button, model, i);
break;
}
case menus::ButtonMenuItemModel::TYPE_BUTTON_LABEL: {
@@ -426,7 +392,7 @@ GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
GTK_BUTTON(button),
RemoveWindowsStyleAccelerators(
UTF16ToUTF8(model->GetLabelAt(i))).c_str());
- SetupButtonShowHandler(button, menu, model, i);
+ SetupButtonShowHandler(button, model, i);
break;
}
}
@@ -485,6 +451,25 @@ void MenuGtk::OnMenuButtonPressed(GtkWidget* menu_item, int command_id) {
}
}
+gboolean MenuGtk::OnMenuTryButtonPressed(GtkWidget* menu_item,
+ int command_id) {
+ gboolean pressed = FALSE;
+ menus::ButtonMenuItemModel* model =
+ reinterpret_cast<menus::ButtonMenuItemModel*>(
+ g_object_get_data(G_OBJECT(menu_item), "button-model"));
+ if (model &&
+ model->IsCommandIdEnabled(command_id) &&
+ !model->DoesCommandIdDismissMenu(command_id)) {
+ if (delegate_)
+ delegate_->CommandWillBeExecuted();
+
+ model->ActivatedCommand(command_id);
+ pressed = TRUE;
+ }
+
+ return pressed;
+}
+
// static
void MenuGtk::WidgetMenuPositionFunc(GtkMenu* menu,
int* x,
@@ -547,10 +532,6 @@ void MenuGtk::PointMenuPositionFunc(GtkMenu* menu,
*y = CalculateMenuYPosition(&screen_rect, &menu_req, NULL, *y);
}
-void MenuGtk::UpdateMenu() {
- gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this);
-}
-
void MenuGtk::ExecuteCommand(menus::MenuModel* model, int id) {
if (delegate_)
delegate_->CommandWillBeExecuted();
@@ -569,6 +550,24 @@ void MenuGtk::OnMenuHidden(GtkWidget* widget) {
}
// static
+void MenuGtk::SetButtonItemInfo(GtkWidget* button, gpointer userdata) {
+ menus::ButtonMenuItemModel* model =
+ reinterpret_cast<menus::ButtonMenuItemModel*>(
+ g_object_get_data(G_OBJECT(button), "button-model"));
+ int index = GPOINTER_TO_INT(g_object_get_data(
+ G_OBJECT(button), "button-model-id"));
+
+ if (model->IsLabelDynamicAt(index)) {
+ std::string label =
+ ConvertAcceleratorsFromWindowsStyle(
+ UTF16ToUTF8(model->GetLabelAt(index)));
+ gtk_button_set_label(GTK_BUTTON(button), label.c_str());
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(button), model->IsEnabledAt(index));
+}
+
+// static
void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) {
if (GTK_IS_SEPARATOR_MENU_ITEM(widget)) {
// We need to explicitly handle this case because otherwise we'll ask the
@@ -605,13 +604,34 @@ void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) {
block_activation_ = false;
}
+ if (GTK_IS_CUSTOM_MENU_ITEM(widget)) {
+ // Iterate across all the buttons to update their visible properties.
+ gtk_custom_menu_item_foreach_button(GTK_CUSTOM_MENU_ITEM(widget),
+ SetButtonItemInfo,
+ userdata);
+ }
+
if (GTK_IS_MENU_ITEM(widget)) {
gtk_widget_set_sensitive(widget, model->IsEnabledAt(id));
- if (model->IsVisibleAt(id))
+ if (model->IsVisibleAt(id)) {
+ // Update the menu item label if it is dynamic.
+ if (model->IsLabelDynamicAt(id)) {
+ std::string label =
+ ConvertAcceleratorsFromWindowsStyle(
+ UTF16ToUTF8(model->GetLabelAt(id)));
+
+#if GTK_CHECK_VERSION(2, 16, 0)
+ gtk_menu_item_set_label(GTK_MENU_ITEM(widget), label.c_str());
+#else
+ gtk_label_set_label(GTK_LABEL(GTK_BIN(widget)->child), label.c_str());
+#endif
+ }
+
gtk_widget_show(widget);
- else
+ } else {
gtk_widget_hide(widget);
+ }
GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
if (submenu) {
diff --git a/chrome/browser/gtk/menu_gtk.h b/chrome/browser/gtk/menu_gtk.h
index 562211d..b4bc98c 100644
--- a/chrome/browser/gtk/menu_gtk.h
+++ b/chrome/browser/gtk/menu_gtk.h
@@ -117,6 +117,9 @@ class MenuGtk {
GtkWidget* widget() const { return menu_; }
+ // Updates all the enabled/checked states and the dynamic labels.
+ void UpdateMenu();
+
private:
// Builds a GtkImageMenuItem.
GtkWidget* BuildMenuItemWithImage(const std::string& label,
@@ -130,9 +133,6 @@ class MenuGtk {
GtkWidget* BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
GtkWidget* menu);
- // Contains implementation for OnMenuShow.
- void UpdateMenu();
-
void ExecuteCommand(menus::MenuModel* model, int id);
// Callback for when a menu item is clicked.
@@ -141,13 +141,21 @@ class MenuGtk {
// Called when one of the buttons are pressed.
CHROMEGTK_CALLBACK_1(MenuGtk, void, OnMenuButtonPressed, int);
+ // Called to maybe activate a button if that button isn't supposed to dismiss
+ // the menu.
+ CHROMEGTK_CALLBACK_1(MenuGtk, gboolean, OnMenuTryButtonPressed, int);
+
// Updates all the menu items' state.
CHROMEGTK_CALLBACK_0(MenuGtk, void, OnMenuShow);
// Sets the activating widget back to a normal appearance.
CHROMEGTK_CALLBACK_0(MenuGtk, void, OnMenuHidden);
- // Sets the check mark and enabled/disabled state on our menu items.
+ // Sets the enable/disabled state and dynamic labels on our menu items.
+ static void SetButtonItemInfo(GtkWidget* button, gpointer userdata);
+
+ // Sets the check mark, enabled/disabled state and dynamic labels on our menu
+ // items.
static void SetMenuItemInfo(GtkWidget* widget, void* raw_menu);
// Queries this object about the menu state.
diff --git a/chrome/browser/wrench_menu_model.cc b/chrome/browser/wrench_menu_model.cc
index bd8b0ac..3273eaf 100644
--- a/chrome/browser/wrench_menu_model.cc
+++ b/chrome/browser/wrench_menu_model.cc
@@ -54,6 +54,9 @@ EncodingMenuModel::EncodingMenuModel(Browser* browser)
Build();
}
+EncodingMenuModel::~EncodingMenuModel() {
+}
+
void EncodingMenuModel::Build() {
EncodingMenuController::EncodingMenuItemList encoding_menu_items;
EncodingMenuController encoding_menu_controller;
@@ -119,6 +122,9 @@ ZoomMenuModel::ZoomMenuModel(menus::SimpleMenuModel::Delegate* delegate)
Build();
}
+ZoomMenuModel::~ZoomMenuModel() {
+}
+
void ZoomMenuModel::Build() {
AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL);
@@ -193,6 +199,10 @@ WrenchMenuModel::~WrenchMenuModel() {
tabstrip_model_->RemoveObserver(this);
}
+bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const {
+ return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS;
+}
+
bool WrenchMenuModel::IsLabelForCommandIdDynamic(int command_id) const {
return command_id == IDC_ZOOM_PERCENT_DISPLAY ||
#if defined(OS_MACOSX)
diff --git a/chrome/browser/wrench_menu_model.h b/chrome/browser/wrench_menu_model.h
index 6f40fde..8011be1 100644
--- a/chrome/browser/wrench_menu_model.h
+++ b/chrome/browser/wrench_menu_model.h
@@ -26,7 +26,7 @@ class EncodingMenuModel : public menus::SimpleMenuModel,
public menus::SimpleMenuModel::Delegate {
public:
explicit EncodingMenuModel(Browser* browser);
- virtual ~EncodingMenuModel() {}
+ virtual ~EncodingMenuModel();
// Overridden from menus::SimpleMenuModel::Delegate:
virtual bool IsCommandIdChecked(int command_id) const;
@@ -47,7 +47,7 @@ class EncodingMenuModel : public menus::SimpleMenuModel,
class ZoomMenuModel : public menus::SimpleMenuModel {
public:
explicit ZoomMenuModel(menus::SimpleMenuModel::Delegate* delegate);
- virtual ~ZoomMenuModel() {}
+ virtual ~ZoomMenuModel();
private:
void Build();
@@ -78,6 +78,9 @@ class WrenchMenuModel : public menus::SimpleMenuModel,
WrenchMenuModel(menus::AcceleratorProvider* provider, Browser* browser);
virtual ~WrenchMenuModel();
+ // Overridden for ButtonMenuItemModel::Delegate:
+ virtual bool DoesCommandIdDismissMenu(int command_id) const;
+
// Overridden for both ButtonMenuItemModel::Delegate and SimpleMenuModel:
virtual bool IsLabelForCommandIdDynamic(int command_id) const;
virtual string16 GetLabelForCommandId(int command_id) const;