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 #ifndef UI_BASE_MODELS_SIMPLE_MENU_MODEL_H_
6 #define UI_BASE_MODELS_SIMPLE_MENU_MODEL_H_
7 
8 #include <string>
9 #include <vector>
10 
11 #include "base/compiler_specific.h"
12 #include "base/macros.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/strings/string16.h"
15 #include "ui/base/accelerators/accelerator.h"
16 #include "ui/base/models/menu_model.h"
17 #include "ui/gfx/image/image.h"
18 
19 namespace gfx {
20 struct VectorIcon;
21 }
22 
23 namespace ui {
24 
25 class ButtonMenuItemModel;
26 
27 // A simple MenuModel implementation with an imperative API for adding menu
28 // items. This makes it easy to construct fixed menus. Menus populated by
29 // dynamic data sources may be better off implementing MenuModel directly.
30 // The breadth of MenuModel is not exposed through this API.
31 class UI_BASE_EXPORT SimpleMenuModel : public MenuModel {
32  public:
33   class UI_BASE_EXPORT Delegate : public AcceleratorProvider {
34    public:
~Delegate()35     ~Delegate() override {}
36 
37     // Makes |command_id| appear toggled true if it's a "check" or "radio" type
38     // menu item. This has no effect for menu items with no boolean state.
39     virtual bool IsCommandIdChecked(int command_id) const;
40 
41     // Delegate should return true if |command_id| should be enabled.
42     virtual bool IsCommandIdEnabled(int command_id) const;
43 
44     // Delegate should return true if |command_id| should be visible.
45     virtual bool IsCommandIdVisible(int command_id) const;
46 
47     // Some command ids have labels and icons that change over time.
48     virtual bool IsItemForCommandIdDynamic(int command_id) const;
49     virtual base::string16 GetLabelForCommandId(int command_id) const;
50     // Gets the icon for the item with the specified id, returning true if there
51     // is an icon, false otherwise.
52     virtual bool GetIconForCommandId(int command_id,
53                                      gfx::Image* icon) const;
54 
55     // Returns the vector icon for the given command id, or null if there is
56     // none. Only used for dynamic menu items.
57     virtual const gfx::VectorIcon* GetVectorIconForCommandId(
58         int command_id) const;
59 
60     // Performs the action associates with the specified command id.
61     // The passed |event_flags| are the flags from the event which issued this
62     // command and they can be examined to find modifier keys.
63     virtual void ExecuteCommand(int command_id, int event_flags) = 0;
64 
65     // Notifies the delegate that the menu is about to show.
66     // Slight hack: Prefix with "On" to make sure this doesn't conflict with
67     // MenuModel::MenuWillShow(), since many classes derive from both
68     // SimpleMenuModel and SimpleMenuModel::Delegate.
69     virtual void OnMenuWillShow(SimpleMenuModel* source);
70 
71     // Notifies the delegate that the menu has closed.
72     virtual void MenuClosed(SimpleMenuModel* source);
73 
74     // AcceleratorProvider overrides:
75     // By default, returns false for all commands. Can be further overridden.
76     bool GetAcceleratorForCommandId(
77         int command_id,
78         ui::Accelerator* accelerator) const override;
79   };
80 
81   // The Delegate can be NULL, though if it is items can't be checked or
82   // disabled.
83   explicit SimpleMenuModel(Delegate* delegate);
84   ~SimpleMenuModel() override;
85 
86   // Methods for adding items to the model.
87   void AddItem(int command_id, const base::string16& label);
88   void AddItemWithStringId(int command_id, int string_id);
89   void AddItemWithIcon(int command_id,
90                        const base::string16& label,
91                        const gfx::ImageSkia& icon);
92   void AddItemWithIcon(int command_id,
93                        const base::string16& label,
94                        const gfx::VectorIcon& icon);
95   void AddItemWithStringIdAndIcon(int command_id,
96                                   int string_id,
97                                   const gfx::ImageSkia& icon);
98   void AddItemWithStringIdAndIcon(int command_id,
99                                   int string_id,
100                                   const gfx::VectorIcon& icon);
101   void AddCheckItem(int command_id, const base::string16& label);
102   void AddCheckItemWithStringId(int command_id, int string_id);
103   void AddRadioItem(int command_id, const base::string16& label, int group_id);
104   void AddRadioItemWithStringId(int command_id, int string_id, int group_id);
105   void AddHighlightedItemWithIcon(int command_id,
106                                   const base::string16& label,
107                                   const gfx::ImageSkia& icon);
108   void AddTitle(const base::string16& label);
109 
110   // Adds a separator of the specified type to the model.
111   // - Adding a separator after another separator is always invalid if they
112   //   differ in type, but silently ignored if they are both NORMAL.
113   // - Adding a separator to an empty model is invalid, unless they are NORMAL
114   //   or SPACING. NORMAL separators are silently ignored if the model is empty.
115   void AddSeparator(MenuSeparatorType separator_type);
116 
117   // These methods take pointers to various sub-models. These models should be
118   // owned by the same owner of this SimpleMenuModel.
119   void AddButtonItem(int command_id, ButtonMenuItemModel* model);
120   void AddSubMenu(int command_id,
121                   const base::string16& label,
122                   MenuModel* model);
123   void AddSubMenuWithStringId(int command_id, int string_id, MenuModel* model);
124   void AddSubMenuWithStringIdAndIcon(int command_id,
125                                      int string_id,
126                                      MenuModel* model,
127                                      const gfx::ImageSkia& icon);
128   void AddSubMenuWithStringIdAndIcon(int command_id,
129                                      int string_id,
130                                      MenuModel* model,
131                                      const gfx::VectorIcon& icon);
132   void AddActionableSubMenu(int command_id,
133                             const base::string16& label,
134                             MenuModel* model);
135   void AddActionableSubmenuWithStringIdAndIcon(int command_id,
136                                                int string_id,
137                                                MenuModel* model,
138                                                const gfx::ImageSkia& icon);
139   void AddActionableSubmenuWithStringIdAndIcon(int command_id,
140                                                int string_id,
141                                                MenuModel* model,
142                                                const gfx::VectorIcon& icon);
143 
144   // Methods for inserting items into the model.
145   void InsertItemAt(int index, int command_id, const base::string16& label);
146   void InsertItemWithStringIdAt(int index, int command_id, int string_id);
147   void InsertSeparatorAt(int index, MenuSeparatorType separator_type);
148   void InsertCheckItemAt(int index,
149                          int command_id,
150                          const base::string16& label);
151   void InsertCheckItemWithStringIdAt(int index, int command_id, int string_id);
152   void InsertRadioItemAt(int index,
153                          int command_id,
154                          const base::string16& label,
155                          int group_id);
156   void InsertRadioItemWithStringIdAt(
157       int index, int command_id, int string_id, int group_id);
158   void InsertSubMenuAt(int index,
159                        int command_id,
160                        const base::string16& label,
161                        MenuModel* model);
162   void InsertSubMenuWithStringIdAt(
163       int index, int command_id, int string_id, MenuModel* model);
164 
165   // Remove item at specified index from the model.
166   void RemoveItemAt(int index);
167 
168   // Sets the icon for the item at |index|.
169   void SetIcon(int index, const gfx::Image& icon);
170 
171   // As above, but uses a VectorIcon. Only one of the two should be set.
172   void SetIcon(int index, const gfx::VectorIcon& icon);
173 
174   // Sets the label for the item at |index|.
175   void SetLabel(int index, const base::string16& label);
176 
177   // Sets the minor text for the item at |index|.
178   void SetMinorText(int index, const base::string16& minor_text);
179 
180   // Sets the minor icon for the item at |index|.
181   void SetMinorIcon(int index, const gfx::VectorIcon& minor_icon);
182 
183   // Sets whether the item at |index| is enabled.
184   void SetEnabledAt(int index, bool enabled);
185 
186   // Sets whether the item at |index| is visible.
187   void SetVisibleAt(int index, bool visible);
188 
189   // Clears all items. Note that it does not free MenuModel of submenu.
190   void Clear();
191 
192   // Returns the index of the item that has the given |command_id|. Returns
193   // -1 if not found.
194   int GetIndexOfCommandId(int command_id) const;
195 
196   // Overridden from MenuModel:
197   bool HasIcons() const override;
198   int GetItemCount() const override;
199   ItemType GetTypeAt(int index) const override;
200   ui::MenuSeparatorType GetSeparatorTypeAt(int index) const override;
201   int GetCommandIdAt(int index) const override;
202   base::string16 GetLabelAt(int index) const override;
203   base::string16 GetMinorTextAt(int index) const override;
204   const gfx::VectorIcon* GetMinorIconAt(int index) const override;
205   bool IsItemDynamicAt(int index) const override;
206   bool GetAcceleratorAt(int index, ui::Accelerator* accelerator) const override;
207   bool IsItemCheckedAt(int index) const override;
208   int GetGroupIdAt(int index) const override;
209   bool GetIconAt(int index, gfx::Image* icon) const override;
210   const gfx::VectorIcon* GetVectorIconAt(int index) const override;
211   ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override;
212   bool IsEnabledAt(int index) const override;
213   bool IsVisibleAt(int index) const override;
214   void ActivatedAt(int index) override;
215   void ActivatedAt(int index, int event_flags) override;
216   MenuModel* GetSubmenuModelAt(int index) const override;
217   void MenuWillShow() override;
218   void MenuWillClose() override;
219 
220  protected:
set_delegate(Delegate * delegate)221   void set_delegate(Delegate* delegate) { delegate_ = delegate; }
delegate()222   Delegate* delegate() { return delegate_; }
223 
224   // One or more of the menu menu items associated with the model has changed.
225   // Do any handling if necessary.
226   virtual void MenuItemsChanged();
227 
228  private:
229   struct Item {
230     Item(Item&&);
231     Item(int command_id, ItemType type, base::string16 label);
232     Item& operator=(Item&&);
233     ~Item();
234 
235     int command_id = 0;
236     ItemType type = TYPE_COMMAND;
237     base::string16 label;
238     base::string16 minor_text;
239     const gfx::VectorIcon* minor_icon = nullptr;
240     gfx::Image icon;
241     const gfx::VectorIcon* vector_icon = nullptr;
242     int group_id = -1;
243     MenuModel* submenu = nullptr;
244     ButtonMenuItemModel* button_model = nullptr;
245     MenuSeparatorType separator_type = NORMAL_SEPARATOR;
246     bool enabled = true;
247     bool visible = true;
248   };
249 
250   typedef std::vector<Item> ItemVector;
251 
252   // Returns |index|.
253   int ValidateItemIndex(int index) const;
254 
255   // Functions for inserting items into |items_|.
256   void AppendItem(Item item);
257   void InsertItemAtIndex(Item item, int index);
258   void ValidateItem(const Item& item);
259 
260   // Notify the delegate that the menu is closed.
261   void OnMenuClosed();
262 
263   ItemVector items_;
264 
265   Delegate* delegate_;
266 
267   base::WeakPtrFactory<SimpleMenuModel> method_factory_{this};
268 
269   DISALLOW_COPY_AND_ASSIGN(SimpleMenuModel);
270 };
271 
272 }  // namespace ui
273 
274 #endif  // UI_BASE_MODELS_SIMPLE_MENU_MODEL_H_
275