Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / base / models / simple_menu_model.cc
bloba8bfdb8eaba4d368ff9a28f0c901690c0b63e778
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/base/models/simple_menu_model.h"
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "ui/base/l10n/l10n_util.h"
10 #include "ui/gfx/image/image.h"
12 namespace ui {
14 const int kSeparatorId = -1;
16 struct SimpleMenuModel::Item {
17 int command_id;
18 base::string16 label;
19 base::string16 sublabel;
20 base::string16 minor_text;
21 gfx::Image icon;
22 ItemType type;
23 int group_id;
24 MenuModel* submenu;
25 ButtonMenuItemModel* button_model;
26 MenuSeparatorType separator_type;
29 ////////////////////////////////////////////////////////////////////////////////
30 // SimpleMenuModel::Delegate, public:
32 bool SimpleMenuModel::Delegate::IsCommandIdVisible(int command_id) const {
33 return true;
36 bool SimpleMenuModel::Delegate::IsItemForCommandIdDynamic(
37 int command_id) const {
38 return false;
41 base::string16 SimpleMenuModel::Delegate::GetLabelForCommandId(
42 int command_id) const {
43 return base::string16();
46 base::string16 SimpleMenuModel::Delegate::GetSublabelForCommandId(
47 int command_id) const {
48 return base::string16();
51 base::string16 SimpleMenuModel::Delegate::GetMinorTextForCommandId(
52 int command_id) const {
53 return base::string16();
56 bool SimpleMenuModel::Delegate::GetIconForCommandId(
57 int command_id, gfx::Image* image_skia) const {
58 return false;
61 void SimpleMenuModel::Delegate::CommandIdHighlighted(int command_id) {
64 void SimpleMenuModel::Delegate::MenuWillShow(SimpleMenuModel* /*source*/) {
67 void SimpleMenuModel::Delegate::MenuClosed(SimpleMenuModel* /*source*/) {
70 ////////////////////////////////////////////////////////////////////////////////
71 // SimpleMenuModel, public:
73 SimpleMenuModel::SimpleMenuModel(Delegate* delegate)
74 : delegate_(delegate),
75 menu_model_delegate_(NULL),
76 method_factory_(this) {
79 SimpleMenuModel::~SimpleMenuModel() {
82 void SimpleMenuModel::AddItem(int command_id, const base::string16& label) {
83 Item item = { command_id, label, base::string16(), base::string16(),
84 gfx::Image(), TYPE_COMMAND, -1, NULL, NULL, NORMAL_SEPARATOR };
85 AppendItem(item);
88 void SimpleMenuModel::AddItemWithStringId(int command_id, int string_id) {
89 AddItem(command_id, l10n_util::GetStringUTF16(string_id));
92 void SimpleMenuModel::AddCheckItem(int command_id,
93 const base::string16& label) {
94 Item item = { command_id, label, base::string16(), base::string16(),
95 gfx::Image(), TYPE_CHECK, -1, NULL, NULL, NORMAL_SEPARATOR };
96 AppendItem(item);
99 void SimpleMenuModel::AddCheckItemWithStringId(int command_id, int string_id) {
100 AddCheckItem(command_id, l10n_util::GetStringUTF16(string_id));
103 void SimpleMenuModel::AddRadioItem(int command_id,
104 const base::string16& label,
105 int group_id) {
106 Item item = { command_id, label, base::string16(), base::string16(),
107 gfx::Image(), TYPE_RADIO, group_id, NULL, NULL,
108 NORMAL_SEPARATOR };
109 AppendItem(item);
112 void SimpleMenuModel::AddRadioItemWithStringId(int command_id, int string_id,
113 int group_id) {
114 AddRadioItem(command_id, l10n_util::GetStringUTF16(string_id), group_id);
117 void SimpleMenuModel::AddSeparator(MenuSeparatorType separator_type) {
118 if (items_.empty()) {
119 if (separator_type == NORMAL_SEPARATOR) {
120 return;
122 DCHECK_EQ(SPACING_SEPARATOR, separator_type);
123 } else if (items_.back().type == TYPE_SEPARATOR) {
124 DCHECK_EQ(NORMAL_SEPARATOR, separator_type);
125 DCHECK_EQ(NORMAL_SEPARATOR, items_.back().separator_type);
126 return;
128 #if !defined(USE_AURA)
129 if (separator_type == SPACING_SEPARATOR)
130 NOTIMPLEMENTED();
131 #endif
132 Item item = { kSeparatorId, base::string16(), base::string16(),
133 base::string16(), gfx::Image(), TYPE_SEPARATOR, -1, NULL, NULL,
134 separator_type };
135 AppendItem(item);
138 void SimpleMenuModel::AddButtonItem(int command_id,
139 ButtonMenuItemModel* model) {
140 Item item = { command_id, base::string16(), base::string16(),
141 base::string16(), gfx::Image(), TYPE_BUTTON_ITEM, -1, NULL,
142 model, NORMAL_SEPARATOR };
143 AppendItem(item);
146 void SimpleMenuModel::AddSubMenu(int command_id,
147 const base::string16& label,
148 MenuModel* model) {
149 Item item = { command_id, label, base::string16(), base::string16(),
150 gfx::Image(), TYPE_SUBMENU, -1, model, NULL, NORMAL_SEPARATOR };
151 AppendItem(item);
154 void SimpleMenuModel::AddSubMenuWithStringId(int command_id,
155 int string_id, MenuModel* model) {
156 AddSubMenu(command_id, l10n_util::GetStringUTF16(string_id), model);
159 void SimpleMenuModel::InsertItemAt(int index,
160 int command_id,
161 const base::string16& label) {
162 Item item = { command_id, label, base::string16(), base::string16(),
163 gfx::Image(), TYPE_COMMAND, -1, NULL, NULL, NORMAL_SEPARATOR };
164 InsertItemAtIndex(item, index);
167 void SimpleMenuModel::InsertItemWithStringIdAt(
168 int index, int command_id, int string_id) {
169 InsertItemAt(index, command_id, l10n_util::GetStringUTF16(string_id));
172 void SimpleMenuModel::InsertSeparatorAt(int index,
173 MenuSeparatorType separator_type) {
174 #if !defined(USE_AURA)
175 if (separator_type != NORMAL_SEPARATOR) {
176 NOTIMPLEMENTED();
178 #endif
179 Item item = { kSeparatorId, base::string16(), base::string16(),
180 base::string16(), gfx::Image(), TYPE_SEPARATOR, -1, NULL, NULL,
181 separator_type };
182 InsertItemAtIndex(item, index);
185 void SimpleMenuModel::InsertCheckItemAt(int index,
186 int command_id,
187 const base::string16& label) {
188 Item item = { command_id, label, base::string16(), base::string16(),
189 gfx::Image(), TYPE_CHECK, -1, NULL, NULL, NORMAL_SEPARATOR };
190 InsertItemAtIndex(item, index);
193 void SimpleMenuModel::InsertCheckItemWithStringIdAt(
194 int index, int command_id, int string_id) {
195 InsertCheckItemAt(index, command_id, l10n_util::GetStringUTF16(string_id));
198 void SimpleMenuModel::InsertRadioItemAt(int index,
199 int command_id,
200 const base::string16& label,
201 int group_id) {
202 Item item = { command_id, label, base::string16(), base::string16(),
203 gfx::Image(), TYPE_RADIO, group_id, NULL, NULL,
204 NORMAL_SEPARATOR };
205 InsertItemAtIndex(item, index);
208 void SimpleMenuModel::InsertRadioItemWithStringIdAt(
209 int index, int command_id, int string_id, int group_id) {
210 InsertRadioItemAt(
211 index, command_id, l10n_util::GetStringUTF16(string_id), group_id);
214 void SimpleMenuModel::InsertSubMenuAt(int index,
215 int command_id,
216 const base::string16& label,
217 MenuModel* model) {
218 Item item = { command_id, label, base::string16(), base::string16(),
219 gfx::Image(), TYPE_SUBMENU, -1, model, NULL,
220 NORMAL_SEPARATOR };
221 InsertItemAtIndex(item, index);
224 void SimpleMenuModel::InsertSubMenuWithStringIdAt(
225 int index, int command_id, int string_id, MenuModel* model) {
226 InsertSubMenuAt(index, command_id, l10n_util::GetStringUTF16(string_id),
227 model);
230 void SimpleMenuModel::RemoveItemAt(int index) {
231 items_.erase(items_.begin() + ValidateItemIndex(index));
232 MenuItemsChanged();
235 void SimpleMenuModel::SetIcon(int index, const gfx::Image& icon) {
236 items_[ValidateItemIndex(index)].icon = icon;
237 MenuItemsChanged();
240 void SimpleMenuModel::SetSublabel(int index, const base::string16& sublabel) {
241 items_[ValidateItemIndex(index)].sublabel = sublabel;
242 MenuItemsChanged();
245 void SimpleMenuModel::SetMinorText(int index,
246 const base::string16& minor_text) {
247 items_[ValidateItemIndex(index)].minor_text = minor_text;
250 void SimpleMenuModel::Clear() {
251 items_.clear();
252 MenuItemsChanged();
255 int SimpleMenuModel::GetIndexOfCommandId(int command_id) {
256 for (ItemVector::iterator i = items_.begin(); i != items_.end(); ++i) {
257 if (i->command_id == command_id)
258 return static_cast<int>(std::distance(items_.begin(), i));
260 return -1;
263 ////////////////////////////////////////////////////////////////////////////////
264 // SimpleMenuModel, MenuModel implementation:
266 bool SimpleMenuModel::HasIcons() const {
267 for (ItemVector::const_iterator i = items_.begin(); i != items_.end(); ++i) {
268 if (!i->icon.IsEmpty())
269 return true;
272 return false;
275 int SimpleMenuModel::GetItemCount() const {
276 return static_cast<int>(items_.size());
279 MenuModel::ItemType SimpleMenuModel::GetTypeAt(int index) const {
280 return items_[ValidateItemIndex(index)].type;
283 ui::MenuSeparatorType SimpleMenuModel::GetSeparatorTypeAt(int index) const {
284 return items_[ValidateItemIndex(index)].separator_type;
287 int SimpleMenuModel::GetCommandIdAt(int index) const {
288 return items_[ValidateItemIndex(index)].command_id;
291 base::string16 SimpleMenuModel::GetLabelAt(int index) const {
292 if (IsItemDynamicAt(index))
293 return delegate_->GetLabelForCommandId(GetCommandIdAt(index));
294 return items_[ValidateItemIndex(index)].label;
297 base::string16 SimpleMenuModel::GetSublabelAt(int index) const {
298 if (IsItemDynamicAt(index))
299 return delegate_->GetSublabelForCommandId(GetCommandIdAt(index));
300 return items_[ValidateItemIndex(index)].sublabel;
303 base::string16 SimpleMenuModel::GetMinorTextAt(int index) const {
304 if (IsItemDynamicAt(index))
305 return delegate_->GetMinorTextForCommandId(GetCommandIdAt(index));
306 return items_[ValidateItemIndex(index)].minor_text;
309 bool SimpleMenuModel::IsItemDynamicAt(int index) const {
310 if (delegate_)
311 return delegate_->IsItemForCommandIdDynamic(GetCommandIdAt(index));
312 return false;
315 bool SimpleMenuModel::GetAcceleratorAt(int index,
316 ui::Accelerator* accelerator) const {
317 if (delegate_) {
318 return delegate_->GetAcceleratorForCommandId(GetCommandIdAt(index),
319 accelerator);
321 return false;
324 bool SimpleMenuModel::IsItemCheckedAt(int index) const {
325 if (!delegate_)
326 return false;
327 MenuModel::ItemType item_type = GetTypeAt(index);
328 return (item_type == TYPE_CHECK || item_type == TYPE_RADIO) ?
329 delegate_->IsCommandIdChecked(GetCommandIdAt(index)) : false;
332 int SimpleMenuModel::GetGroupIdAt(int index) const {
333 return items_[ValidateItemIndex(index)].group_id;
336 bool SimpleMenuModel::GetIconAt(int index, gfx::Image* icon) {
337 if (IsItemDynamicAt(index))
338 return delegate_->GetIconForCommandId(GetCommandIdAt(index), icon);
340 ValidateItemIndex(index);
341 if (items_[index].icon.IsEmpty())
342 return false;
344 *icon = items_[index].icon;
345 return true;
348 ButtonMenuItemModel* SimpleMenuModel::GetButtonMenuItemAt(int index) const {
349 return items_[ValidateItemIndex(index)].button_model;
352 bool SimpleMenuModel::IsEnabledAt(int index) const {
353 int command_id = GetCommandIdAt(index);
354 if (!delegate_ || command_id == kSeparatorId || GetButtonMenuItemAt(index))
355 return true;
356 return delegate_->IsCommandIdEnabled(command_id);
359 bool SimpleMenuModel::IsVisibleAt(int index) const {
360 int command_id = GetCommandIdAt(index);
361 if (!delegate_ || command_id == kSeparatorId || GetButtonMenuItemAt(index))
362 return true;
363 return delegate_->IsCommandIdVisible(command_id);
366 void SimpleMenuModel::HighlightChangedTo(int index) {
367 if (delegate_)
368 delegate_->CommandIdHighlighted(GetCommandIdAt(index));
371 void SimpleMenuModel::ActivatedAt(int index) {
372 if (delegate_)
373 delegate_->ExecuteCommand(GetCommandIdAt(index), 0);
376 void SimpleMenuModel::ActivatedAt(int index, int event_flags) {
377 if (delegate_)
378 delegate_->ExecuteCommand(GetCommandIdAt(index), event_flags);
381 MenuModel* SimpleMenuModel::GetSubmenuModelAt(int index) const {
382 return items_[ValidateItemIndex(index)].submenu;
385 void SimpleMenuModel::MenuWillShow() {
386 if (delegate_)
387 delegate_->MenuWillShow(this);
390 void SimpleMenuModel::MenuClosed() {
391 // Due to how menus work on the different platforms, ActivatedAt will be
392 // called after this. It's more convenient for the delegate to be called
393 // afterwards though, so post a task.
394 base::MessageLoop::current()->PostTask(
395 FROM_HERE,
396 base::Bind(&SimpleMenuModel::OnMenuClosed, method_factory_.GetWeakPtr()));
399 void SimpleMenuModel::SetMenuModelDelegate(
400 ui::MenuModelDelegate* menu_model_delegate) {
401 menu_model_delegate_ = menu_model_delegate;
404 MenuModelDelegate* SimpleMenuModel::GetMenuModelDelegate() const {
405 return menu_model_delegate_;
408 void SimpleMenuModel::OnMenuClosed() {
409 if (delegate_)
410 delegate_->MenuClosed(this);
413 ////////////////////////////////////////////////////////////////////////////////
414 // SimpleMenuModel, Protected:
416 void SimpleMenuModel::MenuItemsChanged() {
419 ////////////////////////////////////////////////////////////////////////////////
420 // SimpleMenuModel, Private:
422 int SimpleMenuModel::ValidateItemIndex(int index) const {
423 CHECK_GE(index, 0);
424 CHECK_LT(static_cast<size_t>(index), items_.size());
425 return index;
428 void SimpleMenuModel::AppendItem(const Item& item) {
429 ValidateItem(item);
430 items_.push_back(item);
431 MenuItemsChanged();
434 void SimpleMenuModel::InsertItemAtIndex(const Item& item, int index) {
435 ValidateItem(item);
436 items_.insert(items_.begin() + index, item);
437 MenuItemsChanged();
440 void SimpleMenuModel::ValidateItem(const Item& item) {
441 #ifndef NDEBUG
442 if (item.type == TYPE_SEPARATOR) {
443 DCHECK_EQ(item.command_id, kSeparatorId);
444 } else {
445 DCHECK_GE(item.command_id, 0);
447 #endif // NDEBUG
450 } // namespace ui