1 // Copyright 2013 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 CHROME_BROWSER_UI_VIEWS_TOOLBAR_APP_MENU_H_
6 #define CHROME_BROWSER_UI_VIEWS_TOOLBAR_APP_MENU_H_
7 
8 #include <map>
9 #include <memory>
10 #include <utility>
11 
12 #include "base/memory/weak_ptr.h"
13 #include "base/scoped_observer.h"
14 #include "base/time/time.h"
15 #include "base/timer/elapsed_timer.h"
16 #include "chrome/browser/ui/global_error/global_error_observer.h"
17 #include "chrome/browser/ui/global_error/global_error_service.h"
18 #include "components/bookmarks/browser/base_bookmark_model_observer.h"
19 #include "ui/base/models/menu_model.h"
20 #include "ui/views/controls/menu/menu_delegate.h"
21 
22 class BookmarkMenuDelegate;
23 class Browser;
24 class ExtensionToolbarMenuView;
25 
26 namespace views {
27 class MenuButtonController;
28 class MenuItemView;
29 class MenuRunner;
30 }
31 
32 // AppMenu adapts the AppMenuModel to view's menu related classes.
33 class AppMenu : public views::MenuDelegate,
34                 public bookmarks::BaseBookmarkModelObserver,
35                 public GlobalErrorObserver,
36                 public base::SupportsWeakPtr<AppMenu> {
37  public:
38   AppMenu(Browser* browser, int run_types, bool alert_reopen_tab_items);
39   AppMenu(const AppMenu&) = delete;
40   AppMenu& operator=(const AppMenu&) = delete;
41   ~AppMenu() override;
42 
43   void Init(ui::MenuModel* model);
44 
45   // Shows the menu relative to the specified controller's button.
46   void RunMenu(views::MenuButtonController* host);
47 
48   // Closes the menu if it is open, otherwise does nothing.
49   void CloseMenu();
50 
51   // Whether the menu is currently visible to the user.
52   bool IsShowing() const;
53 
for_drop()54   bool for_drop() const {
55     return (run_types_ & views::MenuRunner::FOR_DROP) != 0;
56   }
57 
root_menu_item()58   views::MenuItemView* root_menu_item() { return root_; }
59 
60   // MenuDelegate overrides:
61   void GetLabelStyle(int command_id, LabelStyle* style) const override;
62   base::string16 GetTooltipText(int command_id,
63                                 const gfx::Point& p) const override;
64   bool IsTriggerableEvent(views::MenuItemView* menu,
65                           const ui::Event& e) override;
66   bool GetDropFormats(views::MenuItemView* menu,
67                       int* formats,
68                       std::set<ui::ClipboardFormatType>* format_types) override;
69   bool AreDropTypesRequired(views::MenuItemView* menu) override;
70   bool CanDrop(views::MenuItemView* menu,
71                const ui::OSExchangeData& data) override;
72   int GetDropOperation(views::MenuItemView* item,
73                        const ui::DropTargetEvent& event,
74                        DropPosition* position) override;
75   int OnPerformDrop(views::MenuItemView* menu,
76                     DropPosition position,
77                     const ui::DropTargetEvent& event) override;
78   bool ShowContextMenu(views::MenuItemView* source,
79                        int command_id,
80                        const gfx::Point& p,
81                        ui::MenuSourceType source_type) override;
82   bool CanDrag(views::MenuItemView* menu) override;
83   void WriteDragData(views::MenuItemView* sender,
84                      ui::OSExchangeData* data) override;
85   int GetDragOperations(views::MenuItemView* sender) override;
86   int GetMaxWidthForMenu(views::MenuItemView* menu) override;
87   bool IsItemChecked(int command_id) const override;
88   bool IsCommandEnabled(int command_id) const override;
89   void ExecuteCommand(int command_id, int mouse_event_flags) override;
90   bool GetAccelerator(int command_id,
91                       ui::Accelerator* accelerator) const override;
92   void WillShowMenu(views::MenuItemView* menu) override;
93   void WillHideMenu(views::MenuItemView* menu) override;
94   bool ShouldCloseOnDragComplete() override;
95   void OnMenuClosed(views::MenuItemView* menu) override;
96   bool ShouldExecuteCommandWithoutClosingMenu(int command_id,
97                                               const ui::Event& event) override;
98 
99   // bookmarks::BaseBookmarkModelObserver overrides:
100   void BookmarkModelChanged() override;
101 
102   // GlobalErrorObserver:
103   void OnGlobalErrorsChanged() override;
104 
extension_toolbar_for_testing()105   ExtensionToolbarMenuView* extension_toolbar_for_testing() {
106     return extension_toolbar_;
107   }
108 
109  private:
110   class CutCopyPasteView;
111   class RecentTabsMenuModelDelegate;
112   class ZoomView;
113 
114   typedef std::pair<ui::MenuModel*,int> Entry;
115   typedef std::map<int,Entry> CommandIDToEntry;
116 
117   // Populates |parent| with all the child menus in |model|. Recursively invokes
118   // |PopulateMenu| for any submenu.
119   void PopulateMenu(views::MenuItemView* parent,
120                     ui::MenuModel* model);
121 
122   // Adds a new menu item to |parent| at |menu_index| to represent the item in
123   // |model| at |model_index|:
124   // - |menu_index|: position in |parent| to add the new item.
125   // - |model_index|: position in |model| to retrieve information about the
126   //   new menu item.
127   // The returned item's MenuItemView::GetCommand() is the same as that of
128   // |model|->GetCommandIdAt(|model_index|).
129   views::MenuItemView* AddMenuItem(views::MenuItemView* parent,
130                                    int menu_index,
131                                    ui::MenuModel* model,
132                                    int model_index,
133                                    ui::MenuModel::ItemType menu_type);
134 
135   // Invoked from the cut/copy/paste menus. Cancels the current active menu and
136   // activates the menu item in |model| at |index|.
137   void CancelAndEvaluate(ui::ButtonMenuItemModel* model, int index);
138 
139   // Creates the bookmark menu if necessary. Does nothing if already created or
140   // the bookmark model isn't loaded.
141   void CreateBookmarkMenu();
142 
143   // Returns the index of the MenuModel/index pair representing the |command_id|
144   // in |command_id_to_entry_|.
145   int ModelIndexFromCommandId(int command_id) const;
146 
147   // The views menu. Owned by |menu_runner_|.
148   views::MenuItemView* root_ = nullptr;
149 
150   std::unique_ptr<views::MenuRunner> menu_runner_;
151 
152   // Maps from the command ID in model to the model/index pair the item came
153   // from.
154   CommandIDToEntry command_id_to_entry_;
155 
156   // Browser the menu is being shown for.
157   Browser* const browser_;
158 
159   // |CancelAndEvaluate| sets |selected_menu_model_| and |selected_index_|.
160   // If |selected_menu_model_| is non-null after the menu completes
161   // ActivatedAt is invoked. This is done so that ActivatedAt isn't invoked
162   // while the message loop is nested.
163   ui::ButtonMenuItemModel* selected_menu_model_ = nullptr;
164   int selected_index_ = 0;
165 
166   // Used for managing the bookmark menu items.
167   std::unique_ptr<BookmarkMenuDelegate> bookmark_menu_delegate_;
168 
169   // Menu corresponding to IDC_BOOKMARKS_MENU.
170   views::MenuItemView* bookmark_menu_ = nullptr;
171 
172   // Menu corresponding to IDC_FEEDBACK.
173   views::MenuItemView* feedback_menu_item_ = nullptr;
174 
175   // Menu corresponding to IDC_TAKE_SCREENSHOT.
176   views::MenuItemView* screenshot_menu_item_ = nullptr;
177 
178   // The view within the IDC_EXTENSIONS_OVERFLOW_MENU item (only present with
179   // the toolbar action redesign enabled).
180   ExtensionToolbarMenuView* extension_toolbar_ = nullptr;
181 
182   // Used for managing "Recent tabs" menu items.
183   std::unique_ptr<RecentTabsMenuModelDelegate> recent_tabs_menu_model_delegate_;
184 
185   ScopedObserver<GlobalErrorService, GlobalErrorObserver>
186       global_error_observer_{this};
187 
188   // The bit mask of views::MenuRunner::RunTypes.
189   const int run_types_;
190 
191   // Whether to show items relating to reopening the last-closed tab as alerted.
192   const bool alert_reopen_tab_items_;
193 
194   // Records the time from when menu opens to when the user selects a menu item.
195   base::ElapsedTimer menu_opened_timer_;
196 };
197 
198 #endif  // CHROME_BROWSER_UI_VIEWS_TOOLBAR_APP_MENU_H_
199