root/ui/base/models/simple_menu_model.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. IsCommandIdVisible
  2. IsItemForCommandIdDynamic
  3. GetLabelForCommandId
  4. GetSublabelForCommandId
  5. GetMinorTextForCommandId
  6. GetIconForCommandId
  7. CommandIdHighlighted
  8. ExecuteCommand
  9. MenuWillShow
  10. MenuClosed
  11. method_factory_
  12. AddItem
  13. AddItemWithStringId
  14. AddCheckItem
  15. AddCheckItemWithStringId
  16. AddRadioItem
  17. AddRadioItemWithStringId
  18. AddSeparator
  19. RemoveTrailingSeparators
  20. AddButtonItem
  21. AddSubMenu
  22. AddSubMenuWithStringId
  23. InsertItemAt
  24. InsertItemWithStringIdAt
  25. InsertSeparatorAt
  26. InsertCheckItemAt
  27. InsertCheckItemWithStringIdAt
  28. InsertRadioItemAt
  29. InsertRadioItemWithStringIdAt
  30. InsertSubMenuAt
  31. InsertSubMenuWithStringIdAt
  32. RemoveItemAt
  33. SetIcon
  34. SetSublabel
  35. SetMinorText
  36. Clear
  37. GetIndexOfCommandId
  38. HasIcons
  39. GetItemCount
  40. GetTypeAt
  41. GetSeparatorTypeAt
  42. GetCommandIdAt
  43. GetLabelAt
  44. GetSublabelAt
  45. GetMinorTextAt
  46. IsItemDynamicAt
  47. GetAcceleratorAt
  48. IsItemCheckedAt
  49. GetGroupIdAt
  50. GetIconAt
  51. GetButtonMenuItemAt
  52. IsEnabledAt
  53. IsVisibleAt
  54. HighlightChangedTo
  55. ActivatedAt
  56. ActivatedAt
  57. GetSubmenuModelAt
  58. MenuWillShow
  59. MenuClosed
  60. SetMenuModelDelegate
  61. GetMenuModelDelegate
  62. OnMenuClosed
  63. MenuItemsChanged
  64. ValidateItemIndex
  65. AppendItem
  66. InsertItemAtIndex
  67. ValidateItem

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/base/models/simple_menu_model.h"

#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/image/image.h"

namespace ui {

const int kSeparatorId = -1;

struct SimpleMenuModel::Item {
  int command_id;
  base::string16 label;
  base::string16 sublabel;
  base::string16 minor_text;
  gfx::Image icon;
  ItemType type;
  int group_id;
  MenuModel* submenu;
  ButtonMenuItemModel* button_model;
  MenuSeparatorType separator_type;
};

////////////////////////////////////////////////////////////////////////////////
// SimpleMenuModel::Delegate, public:

bool SimpleMenuModel::Delegate::IsCommandIdVisible(int command_id) const {
  return true;
}

bool SimpleMenuModel::Delegate::IsItemForCommandIdDynamic(
    int command_id) const {
  return false;
}

base::string16 SimpleMenuModel::Delegate::GetLabelForCommandId(
    int command_id) const {
  return base::string16();
}

base::string16 SimpleMenuModel::Delegate::GetSublabelForCommandId(
    int command_id) const {
  return base::string16();
}

base::string16 SimpleMenuModel::Delegate::GetMinorTextForCommandId(
    int command_id) const {
  return base::string16();
}

bool SimpleMenuModel::Delegate::GetIconForCommandId(
    int command_id, gfx::Image* image_skia) const {
  return false;
}

void SimpleMenuModel::Delegate::CommandIdHighlighted(int command_id) {
}

void SimpleMenuModel::Delegate::ExecuteCommand(
    int command_id, int event_flags) {
  ExecuteCommand(command_id, event_flags);
}

void SimpleMenuModel::Delegate::MenuWillShow(SimpleMenuModel* /*source*/) {
}

void SimpleMenuModel::Delegate::MenuClosed(SimpleMenuModel* /*source*/) {
}

////////////////////////////////////////////////////////////////////////////////
// SimpleMenuModel, public:

SimpleMenuModel::SimpleMenuModel(Delegate* delegate)
    : delegate_(delegate),
      menu_model_delegate_(NULL),
      method_factory_(this) {
}

SimpleMenuModel::~SimpleMenuModel() {
}

void SimpleMenuModel::AddItem(int command_id, const base::string16& label) {
  Item item = { command_id, label, base::string16(), base::string16(),
                gfx::Image(), TYPE_COMMAND, -1, NULL, NULL, NORMAL_SEPARATOR };
  AppendItem(item);
}

void SimpleMenuModel::AddItemWithStringId(int command_id, int string_id) {
  AddItem(command_id, l10n_util::GetStringUTF16(string_id));
}

void SimpleMenuModel::AddCheckItem(int command_id,
                                   const base::string16& label) {
  Item item = { command_id, label, base::string16(), base::string16(),
                gfx::Image(), TYPE_CHECK, -1, NULL, NULL, NORMAL_SEPARATOR };
  AppendItem(item);
}

void SimpleMenuModel::AddCheckItemWithStringId(int command_id, int string_id) {
  AddCheckItem(command_id, l10n_util::GetStringUTF16(string_id));
}

void SimpleMenuModel::AddRadioItem(int command_id,
                                   const base::string16& label,
                                   int group_id) {
  Item item = { command_id, label, base::string16(), base::string16(),
                gfx::Image(), TYPE_RADIO, group_id, NULL, NULL,
                NORMAL_SEPARATOR };
  AppendItem(item);
}

void SimpleMenuModel::AddRadioItemWithStringId(int command_id, int string_id,
                                               int group_id) {
  AddRadioItem(command_id, l10n_util::GetStringUTF16(string_id), group_id);
}

void SimpleMenuModel::AddSeparator(MenuSeparatorType separator_type) {
  if (items_.empty()) {
    if (separator_type == NORMAL_SEPARATOR) {
      return;
    }
    DCHECK_EQ(SPACING_SEPARATOR, separator_type);
  } else if (items_.back().type == TYPE_SEPARATOR) {
    DCHECK_EQ(NORMAL_SEPARATOR, separator_type);
    DCHECK_EQ(NORMAL_SEPARATOR, items_.back().separator_type);
    return;
  }
#if !defined(USE_AURA)
  if (separator_type != NORMAL_SEPARATOR)
    NOTIMPLEMENTED();
#endif
  Item item = { kSeparatorId, base::string16(), base::string16(),
                base::string16(), gfx::Image(), TYPE_SEPARATOR, -1, NULL, NULL,
                separator_type };
  AppendItem(item);
}

void SimpleMenuModel::RemoveTrailingSeparators() {
  while (!items_.empty() && items_.back().type == TYPE_SEPARATOR)
    items_.pop_back();
  MenuItemsChanged();
}

void SimpleMenuModel::AddButtonItem(int command_id,
                                    ButtonMenuItemModel* model) {
  Item item = { command_id, base::string16(), base::string16(),
                base::string16(), gfx::Image(), TYPE_BUTTON_ITEM, -1, NULL,
                model, NORMAL_SEPARATOR };
  AppendItem(item);
}

void SimpleMenuModel::AddSubMenu(int command_id,
                                 const base::string16& label,
                                 MenuModel* model) {
  Item item = { command_id, label, base::string16(), base::string16(),
                gfx::Image(), TYPE_SUBMENU, -1, model, NULL, NORMAL_SEPARATOR };
  AppendItem(item);
}

void SimpleMenuModel::AddSubMenuWithStringId(int command_id,
                                             int string_id, MenuModel* model) {
  AddSubMenu(command_id, l10n_util::GetStringUTF16(string_id), model);
}

void SimpleMenuModel::InsertItemAt(int index,
                                   int command_id,
                                   const base::string16& label) {
  Item item = { command_id, label, base::string16(), base::string16(),
                gfx::Image(), TYPE_COMMAND, -1, NULL, NULL, NORMAL_SEPARATOR };
  InsertItemAtIndex(item, index);
}

void SimpleMenuModel::InsertItemWithStringIdAt(
    int index, int command_id, int string_id) {
  InsertItemAt(index, command_id, l10n_util::GetStringUTF16(string_id));
}

void SimpleMenuModel::InsertSeparatorAt(int index,
                                        MenuSeparatorType separator_type) {
#if !defined(USE_AURA)
  if (separator_type != NORMAL_SEPARATOR) {
    NOTIMPLEMENTED();
  }
#endif
  Item item = { kSeparatorId, base::string16(), base::string16(),
                base::string16(), gfx::Image(), TYPE_SEPARATOR, -1, NULL, NULL,
                separator_type };
  InsertItemAtIndex(item, index);
}

void SimpleMenuModel::InsertCheckItemAt(int index,
                                        int command_id,
                                        const base::string16& label) {
  Item item = { command_id, label, base::string16(), base::string16(),
                gfx::Image(), TYPE_CHECK, -1, NULL, NULL, NORMAL_SEPARATOR };
  InsertItemAtIndex(item, index);
}

void SimpleMenuModel::InsertCheckItemWithStringIdAt(
    int index, int command_id, int string_id) {
  InsertCheckItemAt(index, command_id, l10n_util::GetStringUTF16(string_id));
}

void SimpleMenuModel::InsertRadioItemAt(int index,
                                        int command_id,
                                        const base::string16& label,
                                        int group_id) {
  Item item = { command_id, label, base::string16(), base::string16(),
                gfx::Image(), TYPE_RADIO, group_id, NULL, NULL,
                NORMAL_SEPARATOR };
  InsertItemAtIndex(item, index);
}

void SimpleMenuModel::InsertRadioItemWithStringIdAt(
    int index, int command_id, int string_id, int group_id) {
  InsertRadioItemAt(
      index, command_id, l10n_util::GetStringUTF16(string_id), group_id);
}

void SimpleMenuModel::InsertSubMenuAt(int index,
                                      int command_id,
                                      const base::string16& label,
                                      MenuModel* model) {
  Item item = { command_id, label, base::string16(), base::string16(),
                gfx::Image(), TYPE_SUBMENU, -1, model, NULL,
                NORMAL_SEPARATOR };
  InsertItemAtIndex(item, index);
}

void SimpleMenuModel::InsertSubMenuWithStringIdAt(
    int index, int command_id, int string_id, MenuModel* model) {
  InsertSubMenuAt(index, command_id, l10n_util::GetStringUTF16(string_id),
                  model);
}

void SimpleMenuModel::RemoveItemAt(int index) {
  items_.erase(items_.begin() + ValidateItemIndex(index));
  MenuItemsChanged();
}

void SimpleMenuModel::SetIcon(int index, const gfx::Image& icon) {
  items_[ValidateItemIndex(index)].icon = icon;
  MenuItemsChanged();
}

void SimpleMenuModel::SetSublabel(int index, const base::string16& sublabel) {
  items_[ValidateItemIndex(index)].sublabel = sublabel;
  MenuItemsChanged();
}

void SimpleMenuModel::SetMinorText(int index,
                                   const base::string16& minor_text) {
  items_[ValidateItemIndex(index)].minor_text = minor_text;
}

void SimpleMenuModel::Clear() {
  items_.clear();
  MenuItemsChanged();
}

int SimpleMenuModel::GetIndexOfCommandId(int command_id) {
  for (ItemVector::iterator i = items_.begin(); i != items_.end(); ++i) {
    if (i->command_id == command_id)
      return static_cast<int>(std::distance(items_.begin(), i));
  }
  return -1;
}

////////////////////////////////////////////////////////////////////////////////
// SimpleMenuModel, MenuModel implementation:

bool SimpleMenuModel::HasIcons() const {
  for (ItemVector::const_iterator i = items_.begin(); i != items_.end(); ++i) {
    if (!i->icon.IsEmpty())
      return true;
  }

  return false;
}

int SimpleMenuModel::GetItemCount() const {
  return static_cast<int>(items_.size());
}

MenuModel::ItemType SimpleMenuModel::GetTypeAt(int index) const {
  return items_[ValidateItemIndex(index)].type;
}

ui::MenuSeparatorType SimpleMenuModel::GetSeparatorTypeAt(int index) const {
  return items_[ValidateItemIndex(index)].separator_type;
}

int SimpleMenuModel::GetCommandIdAt(int index) const {
  return items_[ValidateItemIndex(index)].command_id;
}

base::string16 SimpleMenuModel::GetLabelAt(int index) const {
  if (IsItemDynamicAt(index))
    return delegate_->GetLabelForCommandId(GetCommandIdAt(index));
  return items_[ValidateItemIndex(index)].label;
}

base::string16 SimpleMenuModel::GetSublabelAt(int index) const {
  if (IsItemDynamicAt(index))
    return delegate_->GetSublabelForCommandId(GetCommandIdAt(index));
  return items_[ValidateItemIndex(index)].sublabel;
}

base::string16 SimpleMenuModel::GetMinorTextAt(int index) const {
  if (IsItemDynamicAt(index))
    return delegate_->GetMinorTextForCommandId(GetCommandIdAt(index));
  return items_[ValidateItemIndex(index)].minor_text;
}

bool SimpleMenuModel::IsItemDynamicAt(int index) const {
  if (delegate_)
    return delegate_->IsItemForCommandIdDynamic(GetCommandIdAt(index));
  return false;
}

bool SimpleMenuModel::GetAcceleratorAt(int index,
                                       ui::Accelerator* accelerator) const {
  if (delegate_) {
    return delegate_->GetAcceleratorForCommandId(GetCommandIdAt(index),
                                                 accelerator);
  }
  return false;
}

bool SimpleMenuModel::IsItemCheckedAt(int index) const {
  if (!delegate_)
    return false;
  MenuModel::ItemType item_type = GetTypeAt(index);
  return (item_type == TYPE_CHECK || item_type == TYPE_RADIO) ?
      delegate_->IsCommandIdChecked(GetCommandIdAt(index)) : false;
}

int SimpleMenuModel::GetGroupIdAt(int index) const {
  return items_[ValidateItemIndex(index)].group_id;
}

bool SimpleMenuModel::GetIconAt(int index, gfx::Image* icon) {
  if (IsItemDynamicAt(index))
    return delegate_->GetIconForCommandId(GetCommandIdAt(index), icon);

  ValidateItemIndex(index);
  if (items_[index].icon.IsEmpty())
    return false;

  *icon = items_[index].icon;
  return true;
}

ButtonMenuItemModel* SimpleMenuModel::GetButtonMenuItemAt(int index) const {
  return items_[ValidateItemIndex(index)].button_model;
}

bool SimpleMenuModel::IsEnabledAt(int index) const {
  int command_id = GetCommandIdAt(index);
  if (!delegate_ || command_id == kSeparatorId || GetButtonMenuItemAt(index))
    return true;
  return delegate_->IsCommandIdEnabled(command_id);
}

bool SimpleMenuModel::IsVisibleAt(int index) const {
  int command_id = GetCommandIdAt(index);
  if (!delegate_ || command_id == kSeparatorId || GetButtonMenuItemAt(index))
    return true;
  return delegate_->IsCommandIdVisible(command_id);
}

void SimpleMenuModel::HighlightChangedTo(int index) {
  if (delegate_)
    delegate_->CommandIdHighlighted(GetCommandIdAt(index));
}

void SimpleMenuModel::ActivatedAt(int index) {
  if (delegate_)
    delegate_->ExecuteCommand(GetCommandIdAt(index), 0);
}

void SimpleMenuModel::ActivatedAt(int index, int event_flags) {
  if (delegate_)
    delegate_->ExecuteCommand(GetCommandIdAt(index), event_flags);
}

MenuModel* SimpleMenuModel::GetSubmenuModelAt(int index) const {
  return items_[ValidateItemIndex(index)].submenu;
}

void SimpleMenuModel::MenuWillShow() {
  if (delegate_)
    delegate_->MenuWillShow(this);
}

void SimpleMenuModel::MenuClosed() {
  // Due to how menus work on the different platforms, ActivatedAt will be
  // called after this.  It's more convenient for the delegate to be called
  // afterwards though, so post a task.
  base::MessageLoop::current()->PostTask(
      FROM_HERE,
      base::Bind(&SimpleMenuModel::OnMenuClosed, method_factory_.GetWeakPtr()));
}

void SimpleMenuModel::SetMenuModelDelegate(
      ui::MenuModelDelegate* menu_model_delegate) {
  menu_model_delegate_ = menu_model_delegate;
}

MenuModelDelegate* SimpleMenuModel::GetMenuModelDelegate() const {
  return menu_model_delegate_;
}

void SimpleMenuModel::OnMenuClosed() {
  if (delegate_)
    delegate_->MenuClosed(this);
}

////////////////////////////////////////////////////////////////////////////////
// SimpleMenuModel, Protected:

void SimpleMenuModel::MenuItemsChanged() {
}

////////////////////////////////////////////////////////////////////////////////
// SimpleMenuModel, Private:

int SimpleMenuModel::ValidateItemIndex(int index) const {
  CHECK_GE(index, 0);
  CHECK_LT(static_cast<size_t>(index), items_.size());
  return index;
}

void SimpleMenuModel::AppendItem(const Item& item) {
  ValidateItem(item);
  items_.push_back(item);
  MenuItemsChanged();
}

void SimpleMenuModel::InsertItemAtIndex(const Item& item, int index) {
  ValidateItem(item);
  items_.insert(items_.begin() + index, item);
  MenuItemsChanged();
}

void SimpleMenuModel::ValidateItem(const Item& item) {
#ifndef NDEBUG
  if (item.type == TYPE_SEPARATOR) {
    DCHECK_EQ(item.command_id, kSeparatorId);
  } else {
    DCHECK_GE(item.command_id, 0);
  }
#endif  // NDEBUG
}

}  // namespace ui

/* [<][>][^][v][top][bottom][index][help] */