1 // Copyright 2019 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_EXTENSIONS_EXTENSIONS_TOOLBAR_CONTAINER_H_ 6 #define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_TOOLBAR_CONTAINER_H_ 7 8 #include <map> 9 #include <memory> 10 #include <set> 11 #include <string> 12 #include <vector> 13 14 #include "base/optional.h" 15 #include "chrome/browser/ui/extensions/extensions_container.h" 16 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" 17 #include "chrome/browser/ui/toolbar/toolbar_actions_model.h" 18 #include "chrome/browser/ui/views/toolbar/toolbar_action_view.h" 19 #include "chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h" 20 #include "ui/views/widget/widget_observer.h" 21 22 class Browser; 23 class ExtensionsToolbarButton; 24 class ToolbarActionViewController; 25 26 // Container for extensions shown in the toolbar. These include pinned 27 // extensions and extensions that are 'popped out' transitively to show dialogs 28 // or be called out to the user. 29 // This container is used when the extension-menu experiment is active as a 30 // replacement for BrowserActionsContainer and ToolbarActionsBar which are 31 // intended to be removed. 32 // TODO(crbug.com/943702): Remove note related to extensions menu when cleaning 33 // up after the experiment. 34 class ExtensionsToolbarContainer : public ToolbarIconContainerView, 35 public ExtensionsContainer, 36 public TabStripModelObserver, 37 public ToolbarActionsModel::Observer, 38 public ToolbarActionView::Delegate, 39 public views::WidgetObserver { 40 public: 41 using ToolbarIcons = 42 std::map<ToolbarActionsModel::ActionId, ToolbarActionView*>; 43 44 // Determines how the container displays - specifically whether the menu and 45 // popped out action can be hidden. 46 enum class DisplayMode { 47 // In normal mode, the menu icon and popped-out action is always visible. 48 // Normal mode is used for the main toolbar and in windows where there is 49 // always enough space to show at least two icons. 50 kNormal, 51 // In compact mode, one or both of the menu icon and popped-out action may 52 // be hidden. Compact mode is used in smaller windows (e.g. webapps) where 53 // there may not be enough space to display the buttons. 54 kCompact, 55 }; 56 57 explicit ExtensionsToolbarContainer( 58 Browser* browser, 59 DisplayMode display_mode = DisplayMode::kNormal); 60 ExtensionsToolbarContainer(const ExtensionsToolbarContainer&) = delete; 61 ExtensionsToolbarContainer& operator=(const ExtensionsToolbarContainer&) = 62 delete; 63 ~ExtensionsToolbarContainer() override; 64 extensions_button()65 ExtensionsToolbarButton* extensions_button() const { 66 return extensions_button_; 67 } icons_for_testing()68 const ToolbarIcons& icons_for_testing() const { return icons_; } popup_owner_for_testing()69 ToolbarActionViewController* popup_owner_for_testing() { 70 return popup_owner_; 71 } 72 73 // Get the view corresponding to the extension |id|, if any. 74 ToolbarActionView* GetViewForId(const std::string& id); 75 76 // Pop out and show the extension corresponding to |extension_id|, then show 77 // the Widget when the icon is visible. If the icon is already visible the 78 // action will be posted immediately (not run synchronously). 79 void ShowWidgetForExtension(views::Widget* widget, 80 const std::string& extension_id); 81 82 // Gets the widget that anchors to the extension (or is about to anchor to the 83 // extension, pending pop-out). 84 views::Widget* GetAnchoredWidgetForExtensionForTesting( 85 const std::string& extension_id); 86 87 base::Optional<extensions::ExtensionId> GetExtensionWithOpenContextMenuForTesting()88 GetExtensionWithOpenContextMenuForTesting() { 89 return extension_with_open_context_menu_id_; 90 } 91 92 // ToolbarIconContainerView: 93 void UpdateAllIcons() override; 94 bool GetDropFormats(int* formats, 95 std::set<ui::ClipboardFormatType>* format_types) override; 96 bool AreDropTypesRequired() override; 97 bool CanDrop(const ui::OSExchangeData& data) override; 98 int OnDragUpdated(const ui::DropTargetEvent& event) override; 99 void OnDragExited() override; 100 int OnPerformDrop(const ui::DropTargetEvent& event) override; 101 const char* GetClassName() const override; 102 103 // ExtensionsContainer: 104 ToolbarActionViewController* GetActionForId( 105 const std::string& action_id) override; 106 ToolbarActionViewController* GetPoppedOutAction() const override; 107 void OnContextMenuShown(ToolbarActionViewController* extension) override; 108 void OnContextMenuClosed(ToolbarActionViewController* extension) override; 109 bool IsActionVisibleOnToolbar( 110 const ToolbarActionViewController* action) const override; 111 extensions::ExtensionContextMenuModel::ButtonVisibility GetActionVisibility( 112 const ToolbarActionViewController* action) const override; 113 void UndoPopOut() override; 114 void SetPopupOwner(ToolbarActionViewController* popup_owner) override; 115 void HideActivePopup() override; 116 bool CloseOverflowMenuIfOpen() override; 117 void PopOutAction(ToolbarActionViewController* action, 118 bool is_sticky, 119 const base::Closure& closure) override; 120 bool ShowToolbarActionPopupForAPICall(const std::string& action_id) override; 121 void ShowToolbarActionBubble( 122 std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override; 123 void ShowToolbarActionBubbleAsync( 124 std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override; 125 126 // ToolbarActionView::Delegate: 127 content::WebContents* GetCurrentWebContents() override; 128 bool ShownInsideMenu() const override; 129 bool CanShowIconInToolbar() const override; 130 void OnToolbarActionViewDragDone() override; 131 views::LabelButton* GetOverflowReferenceView() const override; 132 gfx::Size GetToolbarActionSize() override; 133 void WriteDragDataForView(View* sender, 134 const gfx::Point& press_pt, 135 ui::OSExchangeData* data) override; 136 int GetDragOperationsForView(View* sender, const gfx::Point& p) override; 137 bool CanStartDragForView(View* sender, 138 const gfx::Point& press_pt, 139 const gfx::Point& p) override; 140 141 private: 142 // A struct representing the position and action being dragged. 143 struct DropInfo; 144 145 // Pairing of widgets associated with this container and the extension they 146 // are associated with. This is used to keep track of icons that are popped 147 // out due to a widget showing (or being queued to show). 148 struct AnchoredWidget { 149 views::Widget* widget; 150 std::string extension_id; 151 }; 152 153 // Determines whether an action must be visible (i.e. cannot be hidden for any 154 // reason). Returns true if the action is popped out or has an attached 155 // bubble. 156 bool ShouldForceVisibility(const std::string& extension_id) const; 157 158 // Updates the view's visibility state according to 159 // IsActionVisibleOnToolbar(). Note that IsActionVisibleOnToolbar() does not 160 // return View visibility but whether the action should be visible or not 161 // (according to pin and pop-out state). 162 void UpdateIconVisibility(const std::string& extension_id); 163 164 // Set |widget|'s anchor (to the corresponding extension) and then show it. 165 // Posted from |ShowWidgetForExtension|. 166 void AnchorAndShowWidgetImmediately(views::Widget* widget); 167 168 // Creates toolbar actions and icons corresponding to the model. This is only 169 // called in the constructor or when the model initializes and should not be 170 // called for subsequent changes to the model. 171 void CreateActions(); 172 173 // Creates an action and toolbar button for the corresponding ID. 174 void CreateActionForId(const ToolbarActionsModel::ActionId& action_id); 175 176 // Sorts child views to display them in the correct order (pinned actions, 177 // popped out actions, extensions button). 178 void ReorderViews(); 179 180 // Utility function for going from width to icon counts. 181 size_t WidthToIconCount(int x_offset); 182 183 gfx::ImageSkia GetExtensionIcon(ToolbarActionView* extension_view); 184 185 // Sets a pinned extension button's image to be shown/hidden. 186 void SetExtensionIconVisibility(ToolbarActionsModel::ActionId id, 187 bool visible); 188 189 // Calls SetVisible to make sure that the container is showing only when there 190 // are extensions available. 191 void UpdateContainerVisibility(); 192 193 // TabStripModelObserver: 194 void OnTabStripModelChanged( 195 TabStripModel* tab_strip_model, 196 const TabStripModelChange& change, 197 const TabStripSelectionChange& selection) override; 198 199 // ToolbarActionsModel::Observer: 200 void OnToolbarActionAdded(const ToolbarActionsModel::ActionId& action_id, 201 int index) override; 202 void OnToolbarActionRemoved( 203 const ToolbarActionsModel::ActionId& action_id) override; 204 void OnToolbarActionMoved(const ToolbarActionsModel::ActionId& action_id, 205 int index) override; 206 void OnToolbarActionLoadFailed() override; 207 void OnToolbarActionUpdated( 208 const ToolbarActionsModel::ActionId& action_id) override; 209 void OnToolbarVisibleCountChanged() override; 210 void OnToolbarHighlightModeChanged(bool is_highlighting) override; 211 void OnToolbarModelInitialized() override; 212 void OnToolbarPinnedActionsChanged() override; 213 214 // views::WidgetObserver: 215 void OnWidgetClosing(views::Widget* widget) override; 216 void OnWidgetDestroying(views::Widget* widget) override; 217 218 Browser* const browser_; 219 ToolbarActionsModel* const model_; 220 ScopedObserver<ToolbarActionsModel, ToolbarActionsModel::Observer> 221 model_observer_; 222 ExtensionsToolbarButton* const extensions_button_; 223 DisplayMode display_mode_; 224 225 // TODO(pbos): Create actions and icons only for pinned pinned / popped out 226 // actions (lazily). Currently code expects GetActionForId() to return 227 // actions for extensions that aren't visible. 228 // Actions for all extensions. 229 std::vector<std::unique_ptr<ToolbarActionViewController>> actions_; 230 // View for every action, does not imply pinned or currently shown. 231 ToolbarIcons icons_; 232 // Popped-out extension, if any. 233 ToolbarActionViewController* popped_out_action_ = nullptr; 234 // The action that triggered the current popup, if any. 235 ToolbarActionViewController* popup_owner_ = nullptr; 236 // Extension with an open context menu, if any. 237 base::Optional<extensions::ExtensionId> extension_with_open_context_menu_id_; 238 239 // The widgets currently popped out and, for each, the extension it is 240 // associated with. See AnchoredWidget. 241 std::vector<AnchoredWidget> anchored_widgets_; 242 243 // The DropInfo for the current drag-and-drop operation, or a null pointer if 244 // there is none. 245 std::unique_ptr<DropInfo> drop_info_; 246 247 base::WeakPtrFactory<ExtensionsToolbarContainer> weak_ptr_factory_{this}; 248 }; 249 250 #endif // CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_TOOLBAR_CONTAINER_H_ 251