1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_MENUS_SIMPLE_MENU_MODEL_H_
#define UI_MENUS_SIMPLE_MENU_MODEL_H_
#include <optional>
#include <string>
#include <vector>
#include "base/component_export.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/types/pass_key.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/models/image_model.h"
#include "ui/base/models/menu_model.h"
namespace user_education {
class NewBadgeController;
}
class ChromeLabsViewController;
namespace ui {
class ButtonMenuItemModel;
// Boolean-like value that determines if a menu item should be marked as
// "new". Cannot be constructed in a truthy sate except by a fixed set of
// classes, forcing the use of those classes (or wrappers around those classes)
// in order to display as new. This prevents creating menu items which are
// marked as "new" for an extended/indefinite period of time.
class COMPONENT_EXPORT(UI_MENUS) IsNewFeatureAtValue {
public:
IsNewFeatureAtValue() = default;
// Allowed factory classes:
IsNewFeatureAtValue(base::PassKey<user_education::NewBadgeController>,
bool value)
: ui::IsNewFeatureAtValue(value) {}
IsNewFeatureAtValue(base::PassKey<ChromeLabsViewController>, bool value)
: ui::IsNewFeatureAtValue(value) {}
// For other platforms/factories, add appropriate PassKey.
IsNewFeatureAtValue(const IsNewFeatureAtValue&) = default;
IsNewFeatureAtValue& operator=(const IsNewFeatureAtValue&) = default;
// NOLINTNEXTLINE(google-explicit-constructor)
/* implicit */ operator bool() const { return value_; }
bool operator!() const { return !value_; }
static IsNewFeatureAtValue create_for_test(bool value) {
IsNewFeatureAtValue result;
result.value_ = value;
return result;
}
private:
explicit IsNewFeatureAtValue(bool value) : value_(value) {}
bool value_ = false;
};
// A simple MenuModel implementation with an imperative API for adding menu
// items. This makes it easy to construct fixed menus. Menus populated by
// dynamic data sources may be better off implementing MenuModel directly.
// The breadth of MenuModel is not exposed through this API.
class COMPONENT_EXPORT(UI_MENUS) SimpleMenuModel : public MenuModel {
public:
// Default icon size to be used for context menus.
static constexpr int kDefaultIconSize = 16;
class COMPONENT_EXPORT(UI_MENUS) Delegate : public AcceleratorProvider {
public:
~Delegate() override = default;
// Makes |command_id| appear toggled true if it's a "check" or "radio" type
// menu item. This has no effect for menu items with no boolean state.
virtual bool IsCommandIdChecked(int command_id) const;
// Delegate should return true if |command_id| should be enabled.
virtual bool IsCommandIdEnabled(int command_id) const;
// Delegate should return true if |command_id| should be visible.
virtual bool IsCommandIdVisible(int command_id) const;
// Determines if |command_id| should be rendered with an alert for
// in-product help.
virtual bool IsCommandIdAlerted(int command_id) const;
// Determines if |element_id| should be rendered with an alert for
// in-product help.
virtual bool IsElementIdAlerted(ui::ElementIdentifier element_id) const;
// Some command ids have labels and icons that change over time.
virtual bool IsItemForCommandIdDynamic(int command_id) const;
virtual std::u16string GetLabelForCommandId(int command_id) const;
// Gets the icon for the item with the specified id.
virtual ImageModel GetIconForCommandId(int command_id) const;
// Performs the action associates with the specified command id.
// The passed |event_flags| are the flags from the event which issued this
// command and they can be examined to find modifier keys.
virtual void ExecuteCommand(int command_id, int event_flags) = 0;
// Notifies the delegate that the menu is about to show.
// Slight hack: Prefix with "On" to make sure this doesn't conflict with
// MenuModel::MenuWillShow(), since many classes derive from both
// SimpleMenuModel and SimpleMenuModel::Delegate.
virtual void OnMenuWillShow(SimpleMenuModel* source);
// Notifies the delegate that the menu has closed.
virtual void MenuClosed(SimpleMenuModel* source);
// AcceleratorProvider overrides:
// By default, returns false for all commands. Can be further overridden.
bool GetAcceleratorForCommandId(
int command_id,
ui::Accelerator* accelerator) const override;
};
// The Delegate can be NULL, though if it is items can't be checked or
// disabled.
explicit SimpleMenuModel(Delegate* delegate);
SimpleMenuModel(const SimpleMenuModel&) = delete;
SimpleMenuModel& operator=(const SimpleMenuModel&) = delete;
~SimpleMenuModel() override;
// Methods for adding items to the model.
void AddItem(int command_id, const std::u16string& label);
void AddItemWithStringId(int command_id, int string_id);
void AddItemWithIcon(int command_id,
const std::u16string& label,
const ui::ImageModel& icon);
void AddItemWithStringIdAndIcon(int command_id,
int string_id,
const ui::ImageModel& icon);
void AddCheckItem(int command_id, const std::u16string& label);
void AddCheckItemWithStringId(int command_id, int string_id);
void AddRadioItem(int command_id, const std::u16string& label, int group_id);
void AddRadioItemWithStringId(int command_id, int string_id, int group_id);
void AddHighlightedItemWithIcon(int command_id,
const std::u16string& label,
const ui::ImageModel& icon);
void AddTitle(const std::u16string& label);
void AddTitleWithStringId(int string_id);
// Adds a separator of the specified type to the model.
// - Adding a separator after another separator is always invalid if they
// differ in type, but silently ignored if they are both NORMAL.
// - Adding a separator to an empty model is invalid, unless they are NORMAL
// or SPACING. NORMAL separators are silently ignored if the model is empty.
void AddSeparator(MenuSeparatorType separator_type);
// These methods take pointers to various sub-models. These models should be
// owned by the same owner of this SimpleMenuModel.
void AddButtonItem(int command_id, ButtonMenuItemModel* model);
void AddSubMenu(int command_id,
const std::u16string& label,
MenuModel* model);
void AddSubMenuWithStringId(int command_id, int string_id, MenuModel* model);
void AddSubMenuWithIcon(int command_id,
const std::u16string& label,
MenuModel* model,
const ImageModel& icon);
void AddSubMenuWithStringIdAndIcon(int command_id,
int string_id,
MenuModel* model,
const ui::ImageModel& icon);
void AddActionableSubMenu(int command_id,
const std::u16string& label,
MenuModel* model);
void AddActionableSubmenuWithStringIdAndIcon(int command_id,
int string_id,
MenuModel* model,
const ui::ImageModel& icon);
// Methods for inserting items into the model.
void InsertItemAt(size_t index, int command_id, const std::u16string& label);
void InsertItemWithStringIdAt(size_t index, int command_id, int string_id);
void InsertCheckItemAt(size_t index,
int command_id,
const std::u16string& label);
void InsertCheckItemWithStringIdAt(size_t index,
int command_id,
int string_id);
void InsertRadioItemAt(size_t index,
int command_id,
const std::u16string& label,
int group_id);
void InsertRadioItemWithStringIdAt(size_t index,
int command_id,
int string_id,
int group_id);
void InsertTitleWithStringIdAt(size_t index, int string_id);
void InsertSeparatorAt(size_t index, MenuSeparatorType separator_type);
void InsertSubMenuAt(size_t index,
int command_id,
const std::u16string& label,
MenuModel* model);
void InsertSubMenuWithStringIdAt(size_t index,
int command_id,
int string_id,
MenuModel* model);
// Remove item at specified index from the model.
void RemoveItemAt(size_t index);
// Sets the icon for the item at |index|.
void SetIcon(size_t index, const ui::ImageModel& icon);
// Sets the label for the item at |index|.
void SetLabel(size_t index, const std::u16string& label);
// Sets an accelerator for the item at |index|.
//
// Delegate's accelerator will be preferred over one set this way (in case the
// former is set).
void SetAcceleratorAt(size_t index, const ui::Accelerator& accelerator);
// Sets the minor text for the item at |index|.
void SetMinorText(size_t index, const std::u16string& minor_text);
// Sets the minor icon for the item at |index|.
void SetMinorIcon(size_t index, const ui::ImageModel& minor_icon);
// Sets whether the item at |index| is enabled.
void SetEnabledAt(size_t index, bool enabled);
// Sets whether the item at |index| is visible.
void SetVisibleAt(size_t index, bool visible);
// Sets whether the item at |index| is new.
void SetIsNewFeatureAt(size_t index, IsNewFeatureAtValue is_new_feature);
// Sets whether the item at |index| is may have mnemonics.
void SetMayHaveMnemonicsAt(size_t index, bool may_have_mnemonics);
// Sets the accessible name of item at |index|.
void SetAccessibleNameAt(size_t index, std::u16string accessible_name);
// Sets an application-window unique identifier associated with this menu item
// allowing it to be tracked without knowledge of menu-specific command IDs.
void SetElementIdentifierAt(size_t index, ElementIdentifier unique_id);
// Sets the callback that will be run after the menu item has been executed.
void SetExecuteCallbackAt(size_t index,
base::RepeatingCallback<void(int)> callback);
// Clears all items. Note that it does not free MenuModel of submenu.
void Clear();
// Returns the index of the item that has the given |command_id|. Returns
// nullopt if not found.
std::optional<size_t> GetIndexOfCommandId(int command_id) const;
// Sets whether an accelerator will be displayed for item at |index|
// disregarding of the platform.
// Can be used to violate platform UI expectations. Any usage should be agreed
// with the Mac team.
void SetForceShowAcceleratorForItemAt(size_t index,
bool force_show_accelerator_for_item);
// Overridden from MenuModel:
base::WeakPtr<ui::MenuModel> AsWeakPtr() override;
size_t GetItemCount() const override;
ItemType GetTypeAt(size_t index) const override;
ui::MenuSeparatorType GetSeparatorTypeAt(size_t index) const override;
int GetCommandIdAt(size_t index) const override;
std::u16string GetLabelAt(size_t index) const override;
std::u16string GetMinorTextAt(size_t index) const override;
ImageModel GetMinorIconAt(size_t index) const override;
bool IsItemDynamicAt(size_t index) const override;
// First defers to the delegate's GetAcceleratorForCommandId() method to
// retrieve the accelerator for the command associated with the item at
// |index|.
// If no delegate is present or if the delegate does not provide an
// accelerator, GetAcceleratorAt() will retrieve simple menu model's
// accelerator for the item at |index| set by SetAcceleratorAt().
bool GetAcceleratorAt(size_t index,
ui::Accelerator* accelerator) const override;
bool IsItemCheckedAt(size_t index) const override;
int GetGroupIdAt(size_t index) const override;
ImageModel GetIconAt(size_t index) const override;
ui::ButtonMenuItemModel* GetButtonMenuItemAt(size_t index) const override;
bool IsEnabledAt(size_t index) const override;
bool IsVisibleAt(size_t index) const override;
bool IsAlertedAt(size_t index) const override;
bool IsNewFeatureAt(size_t index) const override;
bool MayHaveMnemonicsAt(size_t index) const override;
std::u16string GetAccessibleNameAt(size_t index) const override;
ElementIdentifier GetElementIdentifierAt(size_t index) const override;
void ActivatedAt(size_t index) override;
void ActivatedAt(size_t index, int event_flags) override;
MenuModel* GetSubmenuModelAt(size_t index) const override;
void MenuWillShow() override;
void MenuWillClose() override;
bool GetForceShowAcceleratorForItemAt(size_t index) const override;
protected:
Delegate* delegate() { return delegate_; }
// One or more of the menu menu items associated with the model has changed.
// Do any handling if necessary.
virtual void MenuItemsChanged();
private:
struct Item {
Item(Item&&);
Item(int command_id, ItemType type, std::u16string label);
Item& operator=(Item&&);
~Item();
int command_id = 0;
ItemType type = TYPE_COMMAND;
std::u16string label;
ui::Accelerator accelerator;
std::u16string minor_text;
ImageModel minor_icon;
ImageModel icon;
int group_id = -1;
raw_ptr<MenuModel, DanglingUntriaged> submenu = nullptr;
raw_ptr<ButtonMenuItemModel, DanglingUntriaged> button_model = nullptr;
MenuSeparatorType separator_type = NORMAL_SEPARATOR;
bool enabled = true;
bool visible = true;
bool is_new_feature = false;
bool may_have_mnemonics = true;
bool force_show_accelerator_for_item = false;
std::u16string accessible_name;
ElementIdentifier unique_id;
base::RepeatingCallback<void(int)> on_execute_callback;
};
using ItemVector = std::vector<Item>;
// Returns |index|.
size_t ValidateItemIndex(size_t index) const;
// Functions for inserting items into |items_|.
void AppendItem(Item item);
void InsertItemAtIndex(Item item, size_t index);
void ValidateItem(const Item& item);
// Notify the delegate that the menu is closed.
void OnMenuClosed();
ItemVector items_;
raw_ptr<Delegate, AcrossTasksDanglingUntriaged> delegate_;
base::WeakPtrFactory<SimpleMenuModel> method_factory_{this};
};
} // namespace ui
#endif // UI_MENUS_SIMPLE_MENU_MODEL_H_
|