• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "ui/base/models/simple_menu_model.h"
6 
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"
11 
12 namespace ui {
13 
14 const int kSeparatorId = -1;
15 
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;
27 };
28 
29 ////////////////////////////////////////////////////////////////////////////////
30 // SimpleMenuModel::Delegate, public:
31 
IsCommandIdVisible(int command_id) const32 bool SimpleMenuModel::Delegate::IsCommandIdVisible(int command_id) const {
33   return true;
34 }
35 
IsItemForCommandIdDynamic(int command_id) const36 bool SimpleMenuModel::Delegate::IsItemForCommandIdDynamic(
37     int command_id) const {
38   return false;
39 }
40 
GetLabelForCommandId(int command_id) const41 base::string16 SimpleMenuModel::Delegate::GetLabelForCommandId(
42     int command_id) const {
43   return base::string16();
44 }
45 
GetSublabelForCommandId(int command_id) const46 base::string16 SimpleMenuModel::Delegate::GetSublabelForCommandId(
47     int command_id) const {
48   return base::string16();
49 }
50 
GetMinorTextForCommandId(int command_id) const51 base::string16 SimpleMenuModel::Delegate::GetMinorTextForCommandId(
52     int command_id) const {
53   return base::string16();
54 }
55 
GetIconForCommandId(int command_id,gfx::Image * image_skia) const56 bool SimpleMenuModel::Delegate::GetIconForCommandId(
57     int command_id, gfx::Image* image_skia) const {
58   return false;
59 }
60 
CommandIdHighlighted(int command_id)61 void SimpleMenuModel::Delegate::CommandIdHighlighted(int command_id) {
62 }
63 
ExecuteCommand(int command_id,int event_flags)64 void SimpleMenuModel::Delegate::ExecuteCommand(
65     int command_id, int event_flags) {
66   ExecuteCommand(command_id, event_flags);
67 }
68 
MenuWillShow(SimpleMenuModel *)69 void SimpleMenuModel::Delegate::MenuWillShow(SimpleMenuModel* /*source*/) {
70 }
71 
MenuClosed(SimpleMenuModel *)72 void SimpleMenuModel::Delegate::MenuClosed(SimpleMenuModel* /*source*/) {
73 }
74 
75 ////////////////////////////////////////////////////////////////////////////////
76 // SimpleMenuModel, public:
77 
SimpleMenuModel(Delegate * delegate)78 SimpleMenuModel::SimpleMenuModel(Delegate* delegate)
79     : delegate_(delegate),
80       menu_model_delegate_(NULL),
81       method_factory_(this) {
82 }
83 
~SimpleMenuModel()84 SimpleMenuModel::~SimpleMenuModel() {
85 }
86 
AddItem(int command_id,const base::string16 & label)87 void SimpleMenuModel::AddItem(int command_id, const base::string16& label) {
88   Item item = { command_id, label, base::string16(), base::string16(),
89                 gfx::Image(), TYPE_COMMAND, -1, NULL, NULL, NORMAL_SEPARATOR };
90   AppendItem(item);
91 }
92 
AddItemWithStringId(int command_id,int string_id)93 void SimpleMenuModel::AddItemWithStringId(int command_id, int string_id) {
94   AddItem(command_id, l10n_util::GetStringUTF16(string_id));
95 }
96 
AddCheckItem(int command_id,const base::string16 & label)97 void SimpleMenuModel::AddCheckItem(int command_id,
98                                    const base::string16& label) {
99   Item item = { command_id, label, base::string16(), base::string16(),
100                 gfx::Image(), TYPE_CHECK, -1, NULL, NULL, NORMAL_SEPARATOR };
101   AppendItem(item);
102 }
103 
AddCheckItemWithStringId(int command_id,int string_id)104 void SimpleMenuModel::AddCheckItemWithStringId(int command_id, int string_id) {
105   AddCheckItem(command_id, l10n_util::GetStringUTF16(string_id));
106 }
107 
AddRadioItem(int command_id,const base::string16 & label,int group_id)108 void SimpleMenuModel::AddRadioItem(int command_id,
109                                    const base::string16& label,
110                                    int group_id) {
111   Item item = { command_id, label, base::string16(), base::string16(),
112                 gfx::Image(), TYPE_RADIO, group_id, NULL, NULL,
113                 NORMAL_SEPARATOR };
114   AppendItem(item);
115 }
116 
AddRadioItemWithStringId(int command_id,int string_id,int group_id)117 void SimpleMenuModel::AddRadioItemWithStringId(int command_id, int string_id,
118                                                int group_id) {
119   AddRadioItem(command_id, l10n_util::GetStringUTF16(string_id), group_id);
120 }
121 
AddSeparator(MenuSeparatorType separator_type)122 void SimpleMenuModel::AddSeparator(MenuSeparatorType separator_type) {
123   if (items_.empty()) {
124     if (separator_type == NORMAL_SEPARATOR) {
125       return;
126     }
127     DCHECK_EQ(SPACING_SEPARATOR, separator_type);
128   } else if (items_.back().type == TYPE_SEPARATOR) {
129     DCHECK_EQ(NORMAL_SEPARATOR, separator_type);
130     DCHECK_EQ(NORMAL_SEPARATOR, items_.back().separator_type);
131     return;
132   }
133 #if !defined(USE_AURA)
134   if (separator_type != NORMAL_SEPARATOR)
135     NOTIMPLEMENTED();
136 #endif
137   Item item = { kSeparatorId, base::string16(), base::string16(),
138                 base::string16(), gfx::Image(), TYPE_SEPARATOR, -1, NULL, NULL,
139                 separator_type };
140   AppendItem(item);
141 }
142 
RemoveTrailingSeparators()143 void SimpleMenuModel::RemoveTrailingSeparators() {
144   while (!items_.empty() && items_.back().type == TYPE_SEPARATOR)
145     items_.pop_back();
146   MenuItemsChanged();
147 }
148 
AddButtonItem(int command_id,ButtonMenuItemModel * model)149 void SimpleMenuModel::AddButtonItem(int command_id,
150                                     ButtonMenuItemModel* model) {
151   Item item = { command_id, base::string16(), base::string16(),
152                 base::string16(), gfx::Image(), TYPE_BUTTON_ITEM, -1, NULL,
153                 model, NORMAL_SEPARATOR };
154   AppendItem(item);
155 }
156 
AddSubMenu(int command_id,const base::string16 & label,MenuModel * model)157 void SimpleMenuModel::AddSubMenu(int command_id,
158                                  const base::string16& label,
159                                  MenuModel* model) {
160   Item item = { command_id, label, base::string16(), base::string16(),
161                 gfx::Image(), TYPE_SUBMENU, -1, model, NULL, NORMAL_SEPARATOR };
162   AppendItem(item);
163 }
164 
AddSubMenuWithStringId(int command_id,int string_id,MenuModel * model)165 void SimpleMenuModel::AddSubMenuWithStringId(int command_id,
166                                              int string_id, MenuModel* model) {
167   AddSubMenu(command_id, l10n_util::GetStringUTF16(string_id), model);
168 }
169 
InsertItemAt(int index,int command_id,const base::string16 & label)170 void SimpleMenuModel::InsertItemAt(int index,
171                                    int command_id,
172                                    const base::string16& label) {
173   Item item = { command_id, label, base::string16(), base::string16(),
174                 gfx::Image(), TYPE_COMMAND, -1, NULL, NULL, NORMAL_SEPARATOR };
175   InsertItemAtIndex(item, index);
176 }
177 
InsertItemWithStringIdAt(int index,int command_id,int string_id)178 void SimpleMenuModel::InsertItemWithStringIdAt(
179     int index, int command_id, int string_id) {
180   InsertItemAt(index, command_id, l10n_util::GetStringUTF16(string_id));
181 }
182 
InsertSeparatorAt(int index,MenuSeparatorType separator_type)183 void SimpleMenuModel::InsertSeparatorAt(int index,
184                                         MenuSeparatorType separator_type) {
185 #if !defined(USE_AURA)
186   if (separator_type != NORMAL_SEPARATOR) {
187     NOTIMPLEMENTED();
188   }
189 #endif
190   Item item = { kSeparatorId, base::string16(), base::string16(),
191                 base::string16(), gfx::Image(), TYPE_SEPARATOR, -1, NULL, NULL,
192                 separator_type };
193   InsertItemAtIndex(item, index);
194 }
195 
InsertCheckItemAt(int index,int command_id,const base::string16 & label)196 void SimpleMenuModel::InsertCheckItemAt(int index,
197                                         int command_id,
198                                         const base::string16& label) {
199   Item item = { command_id, label, base::string16(), base::string16(),
200                 gfx::Image(), TYPE_CHECK, -1, NULL, NULL, NORMAL_SEPARATOR };
201   InsertItemAtIndex(item, index);
202 }
203 
InsertCheckItemWithStringIdAt(int index,int command_id,int string_id)204 void SimpleMenuModel::InsertCheckItemWithStringIdAt(
205     int index, int command_id, int string_id) {
206   InsertCheckItemAt(index, command_id, l10n_util::GetStringUTF16(string_id));
207 }
208 
InsertRadioItemAt(int index,int command_id,const base::string16 & label,int group_id)209 void SimpleMenuModel::InsertRadioItemAt(int index,
210                                         int command_id,
211                                         const base::string16& label,
212                                         int group_id) {
213   Item item = { command_id, label, base::string16(), base::string16(),
214                 gfx::Image(), TYPE_RADIO, group_id, NULL, NULL,
215                 NORMAL_SEPARATOR };
216   InsertItemAtIndex(item, index);
217 }
218 
InsertRadioItemWithStringIdAt(int index,int command_id,int string_id,int group_id)219 void SimpleMenuModel::InsertRadioItemWithStringIdAt(
220     int index, int command_id, int string_id, int group_id) {
221   InsertRadioItemAt(
222       index, command_id, l10n_util::GetStringUTF16(string_id), group_id);
223 }
224 
InsertSubMenuAt(int index,int command_id,const base::string16 & label,MenuModel * model)225 void SimpleMenuModel::InsertSubMenuAt(int index,
226                                       int command_id,
227                                       const base::string16& label,
228                                       MenuModel* model) {
229   Item item = { command_id, label, base::string16(), base::string16(),
230                 gfx::Image(), TYPE_SUBMENU, -1, model, NULL,
231                 NORMAL_SEPARATOR };
232   InsertItemAtIndex(item, index);
233 }
234 
InsertSubMenuWithStringIdAt(int index,int command_id,int string_id,MenuModel * model)235 void SimpleMenuModel::InsertSubMenuWithStringIdAt(
236     int index, int command_id, int string_id, MenuModel* model) {
237   InsertSubMenuAt(index, command_id, l10n_util::GetStringUTF16(string_id),
238                   model);
239 }
240 
RemoveItemAt(int index)241 void SimpleMenuModel::RemoveItemAt(int index) {
242   items_.erase(items_.begin() + ValidateItemIndex(index));
243   MenuItemsChanged();
244 }
245 
SetIcon(int index,const gfx::Image & icon)246 void SimpleMenuModel::SetIcon(int index, const gfx::Image& icon) {
247   items_[ValidateItemIndex(index)].icon = icon;
248   MenuItemsChanged();
249 }
250 
SetSublabel(int index,const base::string16 & sublabel)251 void SimpleMenuModel::SetSublabel(int index, const base::string16& sublabel) {
252   items_[ValidateItemIndex(index)].sublabel = sublabel;
253   MenuItemsChanged();
254 }
255 
SetMinorText(int index,const base::string16 & minor_text)256 void SimpleMenuModel::SetMinorText(int index,
257                                    const base::string16& minor_text) {
258   items_[ValidateItemIndex(index)].minor_text = minor_text;
259 }
260 
Clear()261 void SimpleMenuModel::Clear() {
262   items_.clear();
263   MenuItemsChanged();
264 }
265 
GetIndexOfCommandId(int command_id)266 int SimpleMenuModel::GetIndexOfCommandId(int command_id) {
267   for (ItemVector::iterator i = items_.begin(); i != items_.end(); ++i) {
268     if (i->command_id == command_id)
269       return static_cast<int>(std::distance(items_.begin(), i));
270   }
271   return -1;
272 }
273 
274 ////////////////////////////////////////////////////////////////////////////////
275 // SimpleMenuModel, MenuModel implementation:
276 
HasIcons() const277 bool SimpleMenuModel::HasIcons() const {
278   for (ItemVector::const_iterator i = items_.begin(); i != items_.end(); ++i) {
279     if (!i->icon.IsEmpty())
280       return true;
281   }
282 
283   return false;
284 }
285 
GetItemCount() const286 int SimpleMenuModel::GetItemCount() const {
287   return static_cast<int>(items_.size());
288 }
289 
GetTypeAt(int index) const290 MenuModel::ItemType SimpleMenuModel::GetTypeAt(int index) const {
291   return items_[ValidateItemIndex(index)].type;
292 }
293 
GetSeparatorTypeAt(int index) const294 ui::MenuSeparatorType SimpleMenuModel::GetSeparatorTypeAt(int index) const {
295   return items_[ValidateItemIndex(index)].separator_type;
296 }
297 
GetCommandIdAt(int index) const298 int SimpleMenuModel::GetCommandIdAt(int index) const {
299   return items_[ValidateItemIndex(index)].command_id;
300 }
301 
GetLabelAt(int index) const302 base::string16 SimpleMenuModel::GetLabelAt(int index) const {
303   if (IsItemDynamicAt(index))
304     return delegate_->GetLabelForCommandId(GetCommandIdAt(index));
305   return items_[ValidateItemIndex(index)].label;
306 }
307 
GetSublabelAt(int index) const308 base::string16 SimpleMenuModel::GetSublabelAt(int index) const {
309   if (IsItemDynamicAt(index))
310     return delegate_->GetSublabelForCommandId(GetCommandIdAt(index));
311   return items_[ValidateItemIndex(index)].sublabel;
312 }
313 
GetMinorTextAt(int index) const314 base::string16 SimpleMenuModel::GetMinorTextAt(int index) const {
315   if (IsItemDynamicAt(index))
316     return delegate_->GetMinorTextForCommandId(GetCommandIdAt(index));
317   return items_[ValidateItemIndex(index)].minor_text;
318 }
319 
IsItemDynamicAt(int index) const320 bool SimpleMenuModel::IsItemDynamicAt(int index) const {
321   if (delegate_)
322     return delegate_->IsItemForCommandIdDynamic(GetCommandIdAt(index));
323   return false;
324 }
325 
GetAcceleratorAt(int index,ui::Accelerator * accelerator) const326 bool SimpleMenuModel::GetAcceleratorAt(int index,
327                                        ui::Accelerator* accelerator) const {
328   if (delegate_) {
329     return delegate_->GetAcceleratorForCommandId(GetCommandIdAt(index),
330                                                  accelerator);
331   }
332   return false;
333 }
334 
IsItemCheckedAt(int index) const335 bool SimpleMenuModel::IsItemCheckedAt(int index) const {
336   if (!delegate_)
337     return false;
338   MenuModel::ItemType item_type = GetTypeAt(index);
339   return (item_type == TYPE_CHECK || item_type == TYPE_RADIO) ?
340       delegate_->IsCommandIdChecked(GetCommandIdAt(index)) : false;
341 }
342 
GetGroupIdAt(int index) const343 int SimpleMenuModel::GetGroupIdAt(int index) const {
344   return items_[ValidateItemIndex(index)].group_id;
345 }
346 
GetIconAt(int index,gfx::Image * icon)347 bool SimpleMenuModel::GetIconAt(int index, gfx::Image* icon) {
348   if (IsItemDynamicAt(index))
349     return delegate_->GetIconForCommandId(GetCommandIdAt(index), icon);
350 
351   ValidateItemIndex(index);
352   if (items_[index].icon.IsEmpty())
353     return false;
354 
355   *icon = items_[index].icon;
356   return true;
357 }
358 
GetButtonMenuItemAt(int index) const359 ButtonMenuItemModel* SimpleMenuModel::GetButtonMenuItemAt(int index) const {
360   return items_[ValidateItemIndex(index)].button_model;
361 }
362 
IsEnabledAt(int index) const363 bool SimpleMenuModel::IsEnabledAt(int index) const {
364   int command_id = GetCommandIdAt(index);
365   if (!delegate_ || command_id == kSeparatorId || GetButtonMenuItemAt(index))
366     return true;
367   return delegate_->IsCommandIdEnabled(command_id);
368 }
369 
IsVisibleAt(int index) const370 bool SimpleMenuModel::IsVisibleAt(int index) const {
371   int command_id = GetCommandIdAt(index);
372   if (!delegate_ || command_id == kSeparatorId || GetButtonMenuItemAt(index))
373     return true;
374   return delegate_->IsCommandIdVisible(command_id);
375 }
376 
HighlightChangedTo(int index)377 void SimpleMenuModel::HighlightChangedTo(int index) {
378   if (delegate_)
379     delegate_->CommandIdHighlighted(GetCommandIdAt(index));
380 }
381 
ActivatedAt(int index)382 void SimpleMenuModel::ActivatedAt(int index) {
383   if (delegate_)
384     delegate_->ExecuteCommand(GetCommandIdAt(index), 0);
385 }
386 
ActivatedAt(int index,int event_flags)387 void SimpleMenuModel::ActivatedAt(int index, int event_flags) {
388   if (delegate_)
389     delegate_->ExecuteCommand(GetCommandIdAt(index), event_flags);
390 }
391 
GetSubmenuModelAt(int index) const392 MenuModel* SimpleMenuModel::GetSubmenuModelAt(int index) const {
393   return items_[ValidateItemIndex(index)].submenu;
394 }
395 
MenuWillShow()396 void SimpleMenuModel::MenuWillShow() {
397   if (delegate_)
398     delegate_->MenuWillShow(this);
399 }
400 
MenuClosed()401 void SimpleMenuModel::MenuClosed() {
402   // Due to how menus work on the different platforms, ActivatedAt will be
403   // called after this.  It's more convenient for the delegate to be called
404   // afterwards though, so post a task.
405   base::MessageLoop::current()->PostTask(
406       FROM_HERE,
407       base::Bind(&SimpleMenuModel::OnMenuClosed, method_factory_.GetWeakPtr()));
408 }
409 
SetMenuModelDelegate(ui::MenuModelDelegate * menu_model_delegate)410 void SimpleMenuModel::SetMenuModelDelegate(
411       ui::MenuModelDelegate* menu_model_delegate) {
412   menu_model_delegate_ = menu_model_delegate;
413 }
414 
GetMenuModelDelegate() const415 MenuModelDelegate* SimpleMenuModel::GetMenuModelDelegate() const {
416   return menu_model_delegate_;
417 }
418 
OnMenuClosed()419 void SimpleMenuModel::OnMenuClosed() {
420   if (delegate_)
421     delegate_->MenuClosed(this);
422 }
423 
424 ////////////////////////////////////////////////////////////////////////////////
425 // SimpleMenuModel, Protected:
426 
MenuItemsChanged()427 void SimpleMenuModel::MenuItemsChanged() {
428 }
429 
430 ////////////////////////////////////////////////////////////////////////////////
431 // SimpleMenuModel, Private:
432 
ValidateItemIndex(int index) const433 int SimpleMenuModel::ValidateItemIndex(int index) const {
434   CHECK_GE(index, 0);
435   CHECK_LT(static_cast<size_t>(index), items_.size());
436   return index;
437 }
438 
AppendItem(const Item & item)439 void SimpleMenuModel::AppendItem(const Item& item) {
440   ValidateItem(item);
441   items_.push_back(item);
442   MenuItemsChanged();
443 }
444 
InsertItemAtIndex(const Item & item,int index)445 void SimpleMenuModel::InsertItemAtIndex(const Item& item, int index) {
446   ValidateItem(item);
447   items_.insert(items_.begin() + index, item);
448   MenuItemsChanged();
449 }
450 
ValidateItem(const Item & item)451 void SimpleMenuModel::ValidateItem(const Item& item) {
452 #ifndef NDEBUG
453   if (item.type == TYPE_SEPARATOR) {
454     DCHECK_EQ(item.command_id, kSeparatorId);
455   } else {
456     DCHECK_GE(item.command_id, 0);
457   }
458 #endif  // NDEBUG
459 }
460 
461 }  // namespace ui
462