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_BROWSER_ACTION_VIEW_H_ 6 #define CHROME_BROWSER_UI_VIEWS_TOOLBAR_BROWSER_ACTION_VIEW_H_ 7 8 #include <string> 9 10 #include "chrome/browser/extensions/extension_action_icon_factory.h" 11 #include "chrome/browser/extensions/extension_context_menu_model.h" 12 #include "content/public/browser/notification_observer.h" 13 #include "content/public/browser/notification_registrar.h" 14 #include "ui/views/context_menu_controller.h" 15 #include "ui/views/controls/button/menu_button.h" 16 #include "ui/views/controls/button/menu_button_listener.h" 17 #include "ui/views/drag_controller.h" 18 #include "ui/views/view.h" 19 20 class Browser; 21 class BrowserActionButton; 22 class ExtensionAction; 23 24 namespace extensions { 25 class Extension; 26 } 27 28 namespace gfx { 29 class Image; 30 } 31 32 namespace views { 33 class MenuItemView; 34 class MenuRunner; 35 } 36 37 //////////////////////////////////////////////////////////////////////////////// 38 // BrowserActionView 39 // A single entry in the browser action container. This contains the actual 40 // BrowserActionButton, as well as the logic to paint the badge. 41 class BrowserActionView : public views::View { 42 public: 43 // Need DragController here because BrowserActionView could be 44 // dragged/dropped. 45 class Delegate : public views::DragController, 46 public ExtensionContextMenuModel::PopupDelegate { 47 public: 48 // Returns the current tab's ID, or -1 if there is no current tab. 49 virtual int GetCurrentTabId() const = 0; 50 51 // Called when the user clicks on the browser action icon. 52 virtual void OnBrowserActionExecuted(BrowserActionButton* button) = 0; 53 54 // Called when a browser action becomes visible/hidden. 55 virtual void OnBrowserActionVisibilityChanged() = 0; 56 57 protected: ~Delegate()58 virtual ~Delegate() {} 59 }; 60 61 BrowserActionView(const extensions::Extension* extension, 62 Browser* browser, 63 Delegate* delegate); 64 virtual ~BrowserActionView(); 65 button()66 BrowserActionButton* button() { return button_; } 67 68 // Gets browser action button icon with the badge. 69 gfx::ImageSkia GetIconWithBadge(); 70 71 // Overridden from views::View: 72 virtual void Layout() OVERRIDE; 73 virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE; 74 virtual gfx::Size GetPreferredSize() const OVERRIDE; 75 76 protected: 77 // Overridden from views::View to paint the badge on top of children. 78 virtual void PaintChildren(gfx::Canvas* canvas, 79 const views::CullSet& cull_set) OVERRIDE; 80 81 private: 82 // The Browser object this view is associated with. 83 Browser* browser_; 84 85 // Usually a container for this view. 86 Delegate* delegate_; 87 88 // The button this view contains. 89 BrowserActionButton* button_; 90 91 // Extension this view associated with. 92 const extensions::Extension* extension_; 93 94 DISALLOW_COPY_AND_ASSIGN(BrowserActionView); 95 }; 96 97 //////////////////////////////////////////////////////////////////////////////// 98 // BrowserActionButton 99 100 // The BrowserActionButton is a specialization of the MenuButton class. 101 // It acts on a ExtensionAction, in this case a BrowserAction and handles 102 // loading the image for the button asynchronously on the file thread. 103 class BrowserActionButton : public views::MenuButton, 104 public views::ButtonListener, 105 public views::ContextMenuController, 106 public content::NotificationObserver, 107 public ExtensionActionIconFactory::Observer { 108 public: 109 // The IconObserver will receive a notification when the button's icon has 110 // been updated. 111 class IconObserver { 112 public: 113 virtual void OnIconUpdated(const gfx::ImageSkia& icon) = 0; 114 115 protected: ~IconObserver()116 virtual ~IconObserver() {} 117 }; 118 119 BrowserActionButton(const extensions::Extension* extension, 120 Browser* browser_, 121 BrowserActionView::Delegate* delegate); 122 123 // Call this instead of delete. 124 void Destroy(); 125 browser_action()126 ExtensionAction* browser_action() const { return browser_action_; } extension()127 const extensions::Extension* extension() { return extension_; } 128 set_icon_observer(IconObserver * icon_observer)129 void set_icon_observer(IconObserver* icon_observer) { 130 icon_observer_ = icon_observer; 131 } 132 133 // Called to update the display to match the browser action's state. 134 void UpdateState(); 135 136 // Does this button's action have a popup? 137 virtual bool IsPopup(); 138 virtual GURL GetPopupUrl(); 139 140 // Overridden from views::View: 141 virtual bool CanHandleAccelerators() const OVERRIDE; 142 virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE; 143 144 // Overridden from views::ButtonListener: 145 virtual void ButtonPressed(views::Button* sender, 146 const ui::Event& event) OVERRIDE; 147 148 // Overridden from views::ContextMenuController. 149 virtual void ShowContextMenuForView(View* source, 150 const gfx::Point& point, 151 ui::MenuSourceType source_type) OVERRIDE; 152 153 // Overridden from content::NotificationObserver: 154 virtual void Observe(int type, 155 const content::NotificationSource& source, 156 const content::NotificationDetails& details) OVERRIDE; 157 158 // Overriden from ExtensionActionIconFactory::Observer. 159 virtual void OnIconUpdated() OVERRIDE; 160 161 // MenuButton behavior overrides. These methods all default to TextButton 162 // behavior unless this button is a popup. In that case, it uses MenuButton 163 // behavior. MenuButton has the notion of a child popup being shown where the 164 // button will stay in the pushed state until the "menu" (a popup in this 165 // case) is dismissed. 166 virtual bool Activate() OVERRIDE; 167 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; 168 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; 169 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE; 170 virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE; 171 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; 172 173 // Overridden from ui::AcceleratorTarget. 174 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; 175 176 // Notifications when to set button state to pushed/not pushed (for when the 177 // popup/context menu is hidden or shown by the container). 178 void SetButtonPushed(); 179 void SetButtonNotPushed(); 180 181 // Whether the browser action is enabled on this tab. Note that we cannot use 182 // the built-in views enabled/SetEnabled because disabled views do not 183 // receive drag events. 184 bool IsEnabled(int tab_id) const; 185 186 // Returns icon factory for the button. icon_factory()187 ExtensionActionIconFactory& icon_factory() { return icon_factory_; } 188 189 // Gets the icon of this button and its badge. 190 gfx::ImageSkia GetIconWithBadge(); 191 192 // Returns button icon so it can be accessed during tests. 193 gfx::ImageSkia GetIconForTest(); 194 195 protected: 196 // Overridden from views::View: 197 virtual void ViewHierarchyChanged( 198 const ViewHierarchyChangedDetails& details) OVERRIDE; 199 200 private: 201 virtual ~BrowserActionButton(); 202 203 // Register an extension command if the extension has an active one. 204 void MaybeRegisterExtensionCommand(); 205 206 // Unregisters an extension command, if the extension has registered one and 207 // it is active. 208 void MaybeUnregisterExtensionCommand(bool only_if_active); 209 210 // The Browser object this button is associated with. 211 Browser* browser_; 212 213 // The browser action this view represents. The ExtensionAction is not owned 214 // by this class. 215 ExtensionAction* browser_action_; 216 217 // The extension associated with the browser action we're displaying. 218 const extensions::Extension* extension_; 219 220 // The object that will be used to get the browser action icon for us. 221 // It may load the icon asynchronously (in which case the initial icon 222 // returned by the factory will be transparent), so we have to observe it for 223 // updates to the icon. 224 ExtensionActionIconFactory icon_factory_; 225 226 // Delegate that usually represents a container for BrowserActionView. 227 BrowserActionView::Delegate* delegate_; 228 229 // The context menu. This member is non-NULL only when the menu is shown. 230 views::MenuItemView* context_menu_; 231 232 // Used to make sure MaybeRegisterExtensionCommand() is called only once 233 // from ViewHierarchyChanged(). 234 bool called_registered_extension_command_; 235 236 content::NotificationRegistrar registrar_; 237 238 // The extension key binding accelerator this browser action is listening for 239 // (to show the popup). 240 scoped_ptr<ui::Accelerator> keybinding_; 241 242 // Responsible for running the menu. 243 scoped_ptr<views::MenuRunner> menu_runner_; 244 245 // The observer that we need to notify when the icon of the button has been 246 // updated. 247 IconObserver* icon_observer_; 248 249 friend class base::DeleteHelper<BrowserActionButton>; 250 251 DISALLOW_COPY_AND_ASSIGN(BrowserActionButton); 252 }; 253 254 #endif // CHROME_BROWSER_UI_VIEWS_TOOLBAR_BROWSER_ACTION_VIEW_H_ 255