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 CHROME_BROWSER_EXTENSIONS_EXTENSION_CONTEXT_MENU_MODEL_H_
6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_CONTEXT_MENU_MODEL_H_
7 
8 #include <memory>
9 #include <string>
10 
11 #include "base/macros.h"
12 #include "base/optional.h"
13 #include "ui/base/models/simple_menu_model.h"
14 
15 class Browser;
16 class GURL;
17 class Profile;
18 
19 namespace content {
20 class WebContents;
21 }
22 
23 namespace extensions {
24 class ContextMenuMatcher;
25 class Extension;
26 class ExtensionAction;
27 
28 // The context menu model for extension icons.
29 class ExtensionContextMenuModel : public ui::SimpleMenuModel,
30                                   public ui::SimpleMenuModel::Delegate {
31  public:
32   enum MenuEntries {
33     HOME_PAGE = 0,
34     OPTIONS,
35     TOGGLE_VISIBILITY,
36     UNINSTALL,
37     MANAGE_EXTENSIONS,
38     INSPECT_POPUP,
39     PAGE_ACCESS_CANT_ACCESS,
40     PAGE_ACCESS_SUBMENU,
41     PAGE_ACCESS_RUN_ON_CLICK,
42     PAGE_ACCESS_RUN_ON_SITE,
43     PAGE_ACCESS_RUN_ON_ALL_SITES,
44     PAGE_ACCESS_LEARN_MORE,
45     // NOTE: If you update this, you probably need to update the
46     // ContextMenuAction enum below.
47   };
48 
49   // A separate enum to indicate the action taken on the menu. We have two
50   // enums (this and MenuEntries above) to avoid needing to have a single one
51   // with both action-specific values (like kNoAction) and menu-specific values
52   // (like PAGE_ACCESS_SUBMENU).
53   // These values are persisted to logs. Entries should not be renumbered and
54   // numeric values should never be reused. New values should be added before
55   // kMaxValue.
56   enum class ContextMenuAction {
57     kNoAction = 0,
58     kCustomCommand = 1,
59     kHomePage = 2,
60     kOptions = 3,
61     kToggleVisibility = 4,
62     kUninstall = 5,
63     kManageExtensions = 6,
64     kInspectPopup = 7,
65     kPageAccessRunOnClick = 8,
66     kPageAccessRunOnSite = 9,
67     kPageAccessRunOnAllSites = 10,
68     kPageAccessLearnMore = 11,
69     kMaxValue = kPageAccessLearnMore,
70   };
71 
72   // The current visibility of the extension; this affects the "pin" / "unpin"
73   // strings in the menu.
74   // TODO(devlin): Rename this "PinState" when we finish removing the old UI
75   // bits.
76   enum ButtonVisibility {
77     // The extension is pinned on the toolbar.
78     PINNED,
79     // The extension is temporarily visible on the toolbar, as for showing a
80     // popup.
81     TRANSITIVELY_VISIBLE,
82     // The extension is not pinned (and is shown in the extensions menu).
83     UNPINNED,
84   };
85 
86   // Delegate to handle showing an ExtensionAction popup.
87   class PopupDelegate {
88    public:
89     // Called when the user selects the menu item which requests that the
90     // popup be shown and inspected.
91     // The delegate should know which popup to display.
92     virtual void InspectPopup() = 0;
93 
94    protected:
~PopupDelegate()95     virtual ~PopupDelegate() {}
96   };
97 
98   // Creates a menu model for the given extension. If
99   // prefs::kExtensionsUIDeveloperMode is enabled then a menu item
100   // will be shown for "Inspect Popup" which, when selected, will cause
101   // ShowPopupForDevToolsWindow() to be called on |delegate|.
102   ExtensionContextMenuModel(const Extension* extension,
103                             Browser* browser,
104                             ButtonVisibility visibility,
105                             PopupDelegate* delegate,
106                             bool can_show_icon_in_toolbar);
107   ~ExtensionContextMenuModel() override;
108 
109   // SimpleMenuModel::Delegate:
110   bool IsCommandIdChecked(int command_id) const override;
111   bool IsCommandIdVisible(int command_id) const override;
112   bool IsCommandIdEnabled(int command_id) const override;
113   void ExecuteCommand(int command_id, int event_flags) override;
114   void OnMenuWillShow(ui::SimpleMenuModel* source) override;
115   void MenuClosed(ui::SimpleMenuModel* source) override;
116 
page_access_submenu_for_testing()117   ui::SimpleMenuModel* page_access_submenu_for_testing() {
118     return page_access_submenu_.get();
119   }
120 
121  private:
122   void InitMenu(const Extension* extension, ButtonVisibility button_visibility);
123 
124   void CreatePageAccessSubmenu(const Extension* extension);
125 
126   MenuEntries GetCurrentPageAccess(const Extension* extension,
127                                    content::WebContents* web_contents) const;
128 
129   // Returns true if the given page access command is enabled in the menu.
130   bool IsPageAccessCommandEnabled(const Extension& extension,
131                                   const GURL& url,
132                                   int command_id) const;
133 
134   void HandlePageAccessCommand(int command_id,
135                                const Extension* extension) const;
136 
137   // Logs a user action when an option is selected in the page access section of
138   // the context menu.
139   void LogPageAccessAction(int command_id) const;
140 
141   // Gets the extension we are displaying the menu for. Returns NULL if the
142   // extension has been uninstalled and no longer exists.
143   const Extension* GetExtension() const;
144 
145   // Returns the active web contents.
146   content::WebContents* GetActiveWebContents() const;
147 
148   // Appends the extension's context menu items.
149   void AppendExtensionItems();
150 
151   // A copy of the extension's id.
152   std::string extension_id_;
153 
154   // Whether the menu is for a component extension.
155   bool is_component_;
156 
157   // The extension action of the extension we are displaying the menu for (if
158   // it has one, otherwise NULL).
159   ExtensionAction* extension_action_;
160 
161   Browser* const browser_;
162 
163   Profile* profile_;
164 
165   // The delegate which handles the 'inspect popup' menu command (or NULL).
166   PopupDelegate* delegate_;
167 
168   // The visibility of the button at the time the menu opened.
169   ButtonVisibility button_visibility_;
170 
171   const bool can_show_icon_in_toolbar_;
172 
173   // Menu matcher for context menu items specified by the extension.
174   std::unique_ptr<ContextMenuMatcher> extension_items_;
175 
176   std::unique_ptr<ui::SimpleMenuModel> page_access_submenu_;
177 
178   // The action taken by the menu. Has a valid value when the menu is being
179   // shown.
180   base::Optional<ContextMenuAction> action_taken_;
181 
182   DISALLOW_COPY_AND_ASSIGN(ExtensionContextMenuModel);
183 };
184 
185 }  // namespace extensions
186 
187 #endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_CONTEXT_MENU_MODEL_H_
188