rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 1 | // Copyright 2014 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_EXTENSIONS_EXTENSION_ACTION_VIEW_CONTROLLER_H_ |
| 6 | #define CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_ACTION_VIEW_CONTROLLER_H_ |
| 7 | |
avi | 655876a | 2015-12-25 07:18:15 | [diff] [blame^] | 8 | #include "base/macros.h" |
rdevlin.cronin | fb6edb4 | 2015-04-28 18:23:17 | [diff] [blame] | 9 | #include "base/memory/weak_ptr.h" |
rdevlin.cronin | 42efb7dd | 2015-02-11 17:50:52 | [diff] [blame] | 10 | #include "base/scoped_observer.h" |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 11 | #include "chrome/browser/extensions/extension_action_icon_factory.h" |
| 12 | #include "chrome/browser/extensions/extension_context_menu_model.h" |
| 13 | #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" |
rdevlin.cronin | 42efb7dd | 2015-02-11 17:50:52 | [diff] [blame] | 14 | #include "extensions/browser/extension_host_observer.h" |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 15 | #include "ui/gfx/image/image.h" |
| 16 | |
| 17 | class Browser; |
| 18 | class ExtensionAction; |
| 19 | class ExtensionActionPlatformDelegate; |
| 20 | class GURL; |
rdevlin.cronin | fbfcca3 | 2015-07-09 00:28:35 | [diff] [blame] | 21 | class IconWithBadgeImageSource; |
rdevlin.cronin | 5eb91b2 | 2015-04-23 19:39:05 | [diff] [blame] | 22 | class ToolbarActionsBar; |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 23 | |
| 24 | namespace extensions { |
| 25 | class Command; |
| 26 | class Extension; |
rdevlin.cronin | 65115365 | 2014-11-15 00:34:48 | [diff] [blame] | 27 | class ExtensionRegistry; |
rdevlin.cronin | b43d48e | 2015-01-29 17:51:41 | [diff] [blame] | 28 | class ExtensionViewHost; |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 29 | } |
| 30 | |
| 31 | // The platform-independent controller for an ExtensionAction that is shown on |
| 32 | // the toolbar (such as a page or browser action). |
rdevlin.cronin | 65115365 | 2014-11-15 00:34:48 | [diff] [blame] | 33 | // Since this class doesn't own the extension or extension action in question, |
| 34 | // be sure to check for validity using ExtensionIsValid() before using those |
| 35 | // members (see also comments above ExtensionIsValid()). |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 36 | class ExtensionActionViewController |
| 37 | : public ToolbarActionViewController, |
| 38 | public ExtensionActionIconFactory::Observer, |
rdevlin.cronin | 2b74ad8 | 2015-09-17 22:15:54 | [diff] [blame] | 39 | public extensions::ExtensionContextMenuModel::PopupDelegate, |
rdevlin.cronin | 42efb7dd | 2015-02-11 17:50:52 | [diff] [blame] | 40 | public extensions::ExtensionHostObserver { |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 41 | public: |
| 42 | // The different options for showing a popup. |
| 43 | enum PopupShowAction { SHOW_POPUP, SHOW_POPUP_AND_INSPECT }; |
| 44 | |
| 45 | ExtensionActionViewController(const extensions::Extension* extension, |
| 46 | Browser* browser, |
rdevlin.cronin | 5628304c | 2015-10-14 23:07:03 | [diff] [blame] | 47 | ExtensionAction* extension_action, |
rdevlin.cronin | 5eb91b2 | 2015-04-23 19:39:05 | [diff] [blame] | 48 | ToolbarActionsBar* toolbar_actions_bar); |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 49 | ~ExtensionActionViewController() override; |
| 50 | |
| 51 | // ToolbarActionViewController: |
apacible | 3f73e9b3 | 2015-08-21 21:21:08 | [diff] [blame] | 52 | std::string GetId() const override; |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 53 | void SetDelegate(ToolbarActionViewDelegate* delegate) override; |
rdevlin.cronin | 3a57a7f | 2015-07-06 21:22:43 | [diff] [blame] | 54 | gfx::Image GetIcon(content::WebContents* web_contents, |
| 55 | const gfx::Size& size) override; |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 56 | base::string16 GetActionName() const override; |
| 57 | base::string16 GetAccessibleName(content::WebContents* web_contents) const |
| 58 | override; |
| 59 | base::string16 GetTooltip(content::WebContents* web_contents) const override; |
| 60 | bool IsEnabled(content::WebContents* web_contents) const override; |
rdevlin.cronin | f762e8da | 2014-12-02 20:57:10 | [diff] [blame] | 61 | bool WantsToRun(content::WebContents* web_contents) const override; |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 62 | bool HasPopup(content::WebContents* web_contents) const override; |
| 63 | void HidePopup() override; |
| 64 | gfx::NativeView GetPopupNativeView() override; |
rdevlin.cronin | c10ac9e | 2015-01-16 21:10:08 | [diff] [blame] | 65 | ui::MenuModel* GetContextMenu() override; |
rdevlin.cronin | a81394e | 2015-04-30 20:16:56 | [diff] [blame] | 66 | void OnContextMenuClosed() override; |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 67 | bool ExecuteAction(bool by_user) override; |
rdevlin.cronin | 1b9a3a1 | 2014-11-13 17:15:11 | [diff] [blame] | 68 | void UpdateState() override; |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 69 | void RegisterCommand() override; |
rdevlin.cronin | ac27cf3 | 2015-07-09 17:12:34 | [diff] [blame] | 70 | bool DisabledClickOpensMenu() const override; |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 71 | |
| 72 | // ExtensionContextMenuModel::PopupDelegate: |
| 73 | void InspectPopup() override; |
| 74 | |
rdevlin.cronin | 5eb91b2 | 2015-04-23 19:39:05 | [diff] [blame] | 75 | // Closes the active popup (whether it was this action's popup or not). |
| 76 | void HideActivePopup(); |
| 77 | |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 78 | // Populates |command| with the command associated with |extension|, if one |
| 79 | // exists. Returns true if |command| was populated. |
| 80 | bool GetExtensionCommand(extensions::Command* command); |
| 81 | |
rdevlin.cronin | 75c54672 | 2015-05-06 00:26:04 | [diff] [blame] | 82 | const extensions::Extension* extension() const { return extension_.get(); } |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 83 | Browser* browser() { return browser_; } |
| 84 | ExtensionAction* extension_action() { return extension_action_; } |
| 85 | const ExtensionAction* extension_action() const { return extension_action_; } |
| 86 | ToolbarActionViewDelegate* view_delegate() { return view_delegate_; } |
rdevlin.cronin | b43d48e | 2015-01-29 17:51:41 | [diff] [blame] | 87 | bool is_showing_popup() const { return popup_host_ != nullptr; } |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 88 | |
| 89 | void set_icon_observer(ExtensionActionIconFactory::Observer* icon_observer) { |
| 90 | icon_observer_ = icon_observer; |
| 91 | } |
| 92 | |
rdevlin.cronin | fbfcca3 | 2015-07-09 00:28:35 | [diff] [blame] | 93 | scoped_ptr<IconWithBadgeImageSource> GetIconImageSourceForTesting( |
| 94 | content::WebContents* web_contents, |
| 95 | const gfx::Size& size); |
| 96 | |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 97 | private: |
| 98 | // ExtensionActionIconFactory::Observer: |
| 99 | void OnIconUpdated() override; |
| 100 | |
rdevlin.cronin | 42efb7dd | 2015-02-11 17:50:52 | [diff] [blame] | 101 | // ExtensionHostObserver: |
| 102 | void OnExtensionHostDestroyed(const extensions::ExtensionHost* host) override; |
rdevlin.cronin | b43d48e | 2015-01-29 17:51:41 | [diff] [blame] | 103 | |
rdevlin.cronin | 65115365 | 2014-11-15 00:34:48 | [diff] [blame] | 104 | // Checks if the associated |extension| is still valid by checking its |
| 105 | // status in the registry. Since the OnExtensionUnloaded() notifications are |
| 106 | // not in a deterministic order, it's possible that the view tries to refresh |
| 107 | // itself before we're notified to remove it. |
| 108 | bool ExtensionIsValid() const; |
| 109 | |
rdevlin.cronin | 5eb91b2 | 2015-04-23 19:39:05 | [diff] [blame] | 110 | // In some cases (such as when an action is shown in a menu), a substitute |
| 111 | // ToolbarActionViewController should be used for showing popups. This |
| 112 | // returns the preferred controller. |
| 113 | ExtensionActionViewController* GetPreferredPopupViewController(); |
| 114 | |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 115 | // Executes the extension action with |show_action|. If |
| 116 | // |grant_tab_permissions| is true, this will grant the extension active tab |
| 117 | // permissions. Only do this if this was done through a user action (and not |
| 118 | // e.g. an API). Returns true if a popup is shown. |
| 119 | bool ExecuteAction(PopupShowAction show_action, bool grant_tab_permissions); |
| 120 | |
rdevlin.cronin | fb6edb4 | 2015-04-28 18:23:17 | [diff] [blame] | 121 | // Begins the process of showing the popup for the extension action, given the |
| 122 | // associated |popup_url|. |grant_tab_permissions| is true if active tab |
| 123 | // permissions should be given to the extension; this is only true if the |
| 124 | // popup is opened through a user action. |
| 125 | // The popup may not be shown synchronously if the extension is hidden and |
| 126 | // first needs to slide itself out. |
| 127 | // Returns true if a popup will be shown. |
| 128 | bool TriggerPopupWithUrl(PopupShowAction show_action, |
| 129 | const GURL& popup_url, |
| 130 | bool grant_tab_permissions); |
| 131 | |
| 132 | // Shows the popup with the given |host|. |
| 133 | void ShowPopup(scoped_ptr<extensions::ExtensionViewHost> host, |
| 134 | bool grant_tab_permissions, |
| 135 | PopupShowAction show_action); |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 136 | |
rdevlin.cronin | b43d48e | 2015-01-29 17:51:41 | [diff] [blame] | 137 | // Handles cleanup after the popup closes. |
| 138 | void OnPopupClosed(); |
| 139 | |
rdevlin.cronin | fbfcca3 | 2015-07-09 00:28:35 | [diff] [blame] | 140 | // Returns the image source for the icon. |
| 141 | scoped_ptr<IconWithBadgeImageSource> GetIconImageSource( |
| 142 | content::WebContents* web_contents, |
| 143 | const gfx::Size& size); |
| 144 | |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 145 | // The extension associated with the action we're displaying. |
rdevlin.cronin | 75c54672 | 2015-05-06 00:26:04 | [diff] [blame] | 146 | scoped_refptr<const extensions::Extension> extension_; |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 147 | |
| 148 | // The corresponding browser. |
| 149 | Browser* browser_; |
| 150 | |
| 151 | // The browser action this view represents. The ExtensionAction is not owned |
| 152 | // by this class. |
| 153 | ExtensionAction* extension_action_; |
| 154 | |
rdevlin.cronin | 5eb91b2 | 2015-04-23 19:39:05 | [diff] [blame] | 155 | // The owning ToolbarActionsBar, if any. This will be null if this is a |
| 156 | // page action without the toolbar redesign turned on. |
| 157 | // TODO(devlin): Would this be better behind a delegate interface? On the one |
| 158 | // hand, it's odd for this class to know about ToolbarActionsBar, but on the |
| 159 | // other, yet-another-delegate-class might just confuse things. |
| 160 | ToolbarActionsBar* toolbar_actions_bar_; |
| 161 | |
rdevlin.cronin | b43d48e | 2015-01-29 17:51:41 | [diff] [blame] | 162 | // The extension popup's host if the popup is visible; null otherwise. |
| 163 | extensions::ExtensionViewHost* popup_host_; |
| 164 | |
rdevlin.cronin | c10ac9e | 2015-01-16 21:10:08 | [diff] [blame] | 165 | // The context menu model for the extension. |
rdevlin.cronin | 2b74ad8 | 2015-09-17 22:15:54 | [diff] [blame] | 166 | scoped_ptr<extensions::ExtensionContextMenuModel> context_menu_model_; |
rdevlin.cronin | c10ac9e | 2015-01-16 21:10:08 | [diff] [blame] | 167 | |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 168 | // Our view delegate. |
| 169 | ToolbarActionViewDelegate* view_delegate_; |
| 170 | |
| 171 | // The delegate to handle platform-specific implementations. |
| 172 | scoped_ptr<ExtensionActionPlatformDelegate> platform_delegate_; |
| 173 | |
| 174 | // The object that will be used to get the browser action icon for us. |
| 175 | // It may load the icon asynchronously (in which case the initial icon |
| 176 | // returned by the factory will be transparent), so we have to observe it for |
| 177 | // updates to the icon. |
| 178 | ExtensionActionIconFactory icon_factory_; |
| 179 | |
| 180 | // An additional observer that we need to notify when the icon of the button |
| 181 | // has been updated. |
| 182 | ExtensionActionIconFactory::Observer* icon_observer_; |
| 183 | |
rdevlin.cronin | 65115365 | 2014-11-15 00:34:48 | [diff] [blame] | 184 | // The associated ExtensionRegistry; cached for quick checking. |
| 185 | extensions::ExtensionRegistry* extension_registry_; |
| 186 | |
rdevlin.cronin | 42efb7dd | 2015-02-11 17:50:52 | [diff] [blame] | 187 | ScopedObserver<extensions::ExtensionHost, extensions::ExtensionHostObserver> |
| 188 | popup_host_observer_; |
rdevlin.cronin | b43d48e | 2015-01-29 17:51:41 | [diff] [blame] | 189 | |
rdevlin.cronin | fb6edb4 | 2015-04-28 18:23:17 | [diff] [blame] | 190 | base::WeakPtrFactory<ExtensionActionViewController> weak_factory_; |
| 191 | |
rdevlin.cronin | 0953074 | 2014-11-03 19:23:28 | [diff] [blame] | 192 | DISALLOW_COPY_AND_ASSIGN(ExtensionActionViewController); |
| 193 | }; |
| 194 | |
| 195 | #endif // CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_ACTION_VIEW_CONTROLLER_H_ |