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_TOOLBAR_TOOLBAR_ACTIONS_BAR_H_ 6 #define CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_BAR_H_ 7 8 #include <stddef.h> 9 10 #include <memory> 11 #include <vector> 12 13 #include "base/callback.h" 14 #include "base/macros.h" 15 #include "base/memory/weak_ptr.h" 16 #include "base/observer_list.h" 17 #include "base/optional.h" 18 #include "base/scoped_observer.h" 19 #include "chrome/browser/ui/extensions/extensions_container.h" 20 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" 21 #include "chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h" 22 #include "chrome/browser/ui/toolbar/toolbar_actions_model.h" 23 #include "ui/gfx/animation/tween.h" 24 #include "ui/gfx/geometry/size.h" 25 26 namespace user_prefs { 27 class PrefRegistrySyncable; 28 } 29 30 class BrowserWindow; 31 class ToolbarActionsBarDelegate; 32 class ToolbarActionsBarObserver; 33 class ToolbarActionViewController; 34 35 // A platform-independent version of the container for toolbar actions, 36 // including extension actions and component actions. 37 // 38 // This is a per-window instance, unlike the ToolbarActionsModel, which is 39 // per-profile. In most cases, ordering and visible count will be identical 40 // between the base model and the window; however, there are exceptions in the 41 // case of very small windows (which may be too narrow to display all the 42 // icons), or windows in which an action is "popped out", resulting in a 43 // re-ordering. 44 // 45 // This can come in two flavors, main and "overflow". The main bar is visible 46 // next to the omnibox, and the overflow bar is visible inside the chrome 47 // app menu. The main bar can have only a single row of icons with flexible 48 // width, whereas the overflow bar has multiple rows of icons with a fixed 49 // width (the width of the menu). 50 class ToolbarActionsBar : public ExtensionsContainer, 51 public ToolbarActionsModel::Observer, 52 public TabStripModelObserver { 53 public: 54 using ToolbarActions = 55 std::vector<std::unique_ptr<ToolbarActionViewController>>; 56 57 // A struct to contain the platform settings. 58 struct PlatformSettings { 59 PlatformSettings(); 60 61 // The spacing between each of the icons, between the start of the 62 // container and the first item, and between the last item and end of 63 // the container. 64 int item_spacing; 65 // The number of icons per row in the overflow menu. 66 int icons_per_overflow_menu_row; 67 }; 68 69 // The type of drag that occurred in a drag-and-drop operation. 70 enum DragType { 71 // The icon was dragged to the same container it started in. 72 DRAG_TO_SAME, 73 // The icon was dragged from the main container to the overflow. 74 DRAG_TO_OVERFLOW, 75 // The icon was dragged from the overflow container to the main. 76 DRAG_TO_MAIN, 77 }; 78 79 enum HighlightType { 80 HIGHLIGHT_NONE, 81 HIGHLIGHT_WARNING, 82 }; 83 84 ToolbarActionsBar(ToolbarActionsBarDelegate* delegate, 85 Browser* browser, 86 ToolbarActionsBar* main_bar); 87 ~ToolbarActionsBar() override; 88 89 // Gets the ToolbarActionsBar from the given BrowserWindow. This method is 90 // essentially deprecated. Use BrowserWindow::GetExtensionsContainer instead. 91 static ToolbarActionsBar* FromBrowserWindow(BrowserWindow* window); 92 93 // Registers profile preferences. 94 static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); 95 96 // Returns the size of the area where the action icon resides. 97 static gfx::Size GetIconAreaSize(); 98 99 // Returns the size of ToolbarActionView. 100 gfx::Size GetViewSize() const; 101 102 // Returns the default/full size for the toolbar; this does *not* reflect any 103 // animations that may be running. 104 gfx::Size GetFullSize() const; 105 106 // Returns the [minimum|maximum] possible width for the toolbar. 107 virtual int GetMinimumWidth() const; 108 int GetMaximumWidth() const; 109 110 // Returns the width for the given number of icons. 111 int IconCountToWidth(size_t icons) const; 112 113 // Returns the number of icons that can fit within the given width. 114 size_t WidthToIconCount(int width) const; 115 116 // Returns the number of icons that should be displayed if space allows. Can 117 // be overridden by children to impose a smaller limit on the number of icons. 118 virtual size_t GetIconCount() const; 119 120 // Returns the starting index (inclusive) for displayable icons. 121 size_t GetStartIndexInBounds() const; 122 123 // Returns the ending index (exclusive) for displayable icons. 124 size_t GetEndIndexInBounds() const; 125 126 // Returns true if an overflow container is necessary to display any other 127 // icons for this particular window. This is different than 128 // ToolbarActionsModel::all_icons_visible() because the ToolbarActionsBar 129 // is limited to a single window, whereas the model is the underlying model 130 // of *all* windows, independent of size. As such, the model is identical 131 // between a very wide window and a very narrow window, and the user's stored 132 // preference may be to have all icons visible. But if the very narrow window 133 // doesn't have the width to display all those actions, some will need to be 134 // implicitly pushed to the overflow, even though the user's global preference 135 // has not changed. 136 bool NeedsOverflow() const; 137 138 // Returns the frame (bounds) that the specified index should have, taking 139 // into account if this is the main or overflow bar. If this is the overflow 140 // bar and the index should not be displayed (i.e., it is shown on the main 141 // bar), returns an empty rect. 142 gfx::Rect GetFrameForIndex(size_t index) const; 143 144 // Returns the actions in the proper order; this may differ from the 145 // underlying order in the case of actions being popped out to show a popup. 146 std::vector<ToolbarActionViewController*> GetActions() const; 147 148 // Creates the toolbar actions. 149 void CreateActions(); 150 151 // Deletes all toolbar actions. 152 void DeleteActions(); 153 154 // Updates all the toolbar actions. 155 void Update(); 156 157 // Sets the width for the overflow menu rows. 158 void SetOverflowRowWidth(int width); 159 160 // Notifies the ToolbarActionsBar that a user completed a resize gesture, and 161 // the new width is |width|. 162 void OnResizeComplete(int width); 163 164 // Notifies the ToolbarActionsBar that the user has started dragging the 165 // action at index |index_of_dragged_item|. 166 void OnDragStarted(size_t index_of_dragged_item); 167 168 // Notifies the ToolbarActionsBar that a drag-and-drop sequence ended. This 169 // may not coincide with OnDragDrop(), since the view may be dropped somewhere 170 // else. 171 void OnDragEnded(); 172 173 // Notifies the ToolbarActionsBar that a user completed a drag and drop event, 174 // and dragged the view from |dragged_index| to |dropped_index|. 175 // |drag_type| indicates whether or not the icon was dragged between the 176 // overflow and main containers. 177 // The main container should handle all drag/drop notifications. 178 void OnDragDrop(int dragged_index, 179 int dropped_index, 180 DragType drag_type); 181 182 // The index of the action currently being dragged, or |base::nullopt| if 183 // no drag is in progress. Should only be called on the main bar. 184 const base::Optional<size_t> IndexOfDraggedItem() const; 185 186 // Notifies the ToolbarActionsBar that the delegate finished animating. 187 void OnAnimationEnded(); 188 189 // Called when the active bubble is closed. 190 void OnBubbleClosed(); 191 192 // Add or remove an observer. 193 void AddObserver(ToolbarActionsBarObserver* observer); 194 void RemoveObserver(ToolbarActionsBarObserver* observer); 195 196 // Returns the underlying toolbar actions, but does not order them. Primarily 197 // for use in testing. toolbar_actions_unordered()198 const ToolbarActions& toolbar_actions_unordered() const { 199 return toolbar_actions_; 200 } enabled()201 bool enabled() const { return model_ != nullptr; } suppress_layout()202 bool suppress_layout() const { return suppress_layout_; } suppress_animation()203 bool suppress_animation() const { 204 return suppress_animation_ || disable_animations_for_testing_; 205 } is_highlighting()206 bool is_highlighting() const { return model_ && model_->is_highlighting(); } highlight_type()207 ToolbarActionsModel::HighlightType highlight_type() const { 208 return model_ ? model_->highlight_type() 209 : ToolbarActionsModel::HIGHLIGHT_NONE; 210 } platform_settings()211 const PlatformSettings& platform_settings() const { 212 return platform_settings_; 213 } popup_owner()214 ToolbarActionViewController* popup_owner() { return popup_owner_; } in_overflow_mode()215 bool in_overflow_mode() const { return main_bar_ != nullptr; } is_showing_bubble()216 bool is_showing_bubble() const { return is_showing_bubble_; } 217 is_drag_in_progress()218 bool is_drag_in_progress() const { 219 return index_of_dragged_item_ != base::nullopt; 220 } 221 delegate_for_test()222 ToolbarActionsBarDelegate* delegate_for_test() { return delegate_; } 223 224 // During testing we can disable animations by setting this flag to true, 225 // so that the bar resizes instantly, instead of having to poll it while it 226 // animates to open/closed status. 227 static bool disable_animations_for_testing_; 228 static void set_extension_bubble_appearance_wait_time_for_testing( 229 int time_in_seconds); 230 231 // ExtensionsContainer: 232 ToolbarActionViewController* GetActionForId( 233 const std::string& action_id) override; 234 ToolbarActionViewController* GetPoppedOutAction() const override; 235 bool IsActionVisibleOnToolbar( 236 const ToolbarActionViewController* action) const override; 237 extensions::ExtensionContextMenuModel::ButtonVisibility GetActionVisibility( 238 const ToolbarActionViewController* action) const override; 239 void UndoPopOut() override; 240 void SetPopupOwner(ToolbarActionViewController* popup_owner) override; 241 void HideActivePopup() override; 242 bool CloseOverflowMenuIfOpen() override; 243 void PopOutAction(ToolbarActionViewController* action, 244 bool is_sticky, 245 const base::Closure& closure) override; 246 bool ShowToolbarActionPopupForAPICall(const std::string& id) override; 247 void ShowToolbarActionBubble( 248 std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override; 249 void ShowToolbarActionBubbleAsync( 250 std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override; 251 252 private: 253 // Returns the insets by which the icon area bounds (See GetIconAreaRect()) 254 // are insetted. This defines the amount of paddings around the icon area. 255 virtual gfx::Insets GetIconAreaInsets() const; 256 257 // Returns the number of icons that can fit within the given width. 258 size_t WidthToIconCountUnclamped(int width) const; 259 260 // ToolbarActionsModel::Observer: 261 void OnToolbarActionAdded(const ToolbarActionsModel::ActionId& action_id, 262 int index) override; 263 void OnToolbarActionRemoved( 264 const ToolbarActionsModel::ActionId& action_id) override; 265 void OnToolbarActionMoved(const ToolbarActionsModel::ActionId& action_id, 266 int index) override; 267 void OnToolbarActionLoadFailed() override; 268 void OnToolbarActionUpdated( 269 const ToolbarActionsModel::ActionId& action_id) override; 270 void OnToolbarVisibleCountChanged() override; 271 void OnToolbarHighlightModeChanged(bool is_highlighting) override; 272 void OnToolbarModelInitialized() override; 273 void OnToolbarPinnedActionsChanged() override; 274 275 // TabStripModelObserver: 276 void OnTabStripModelChanged( 277 TabStripModel* tab_strip_model, 278 const TabStripModelChange& change, 279 const TabStripSelectionChange& selection) override; 280 281 // Resizes the delegate (if necessary) to the preferred size using the given 282 // |tween_type|. 283 void ResizeDelegate(gfx::Tween::Type tween_type); 284 285 // Returns the current web contents. 286 content::WebContents* GetCurrentWebContents(); 287 288 // Reorders the toolbar actions to reflect the model and, optionally, to 289 // "pop out" any overflowed actions that want to run (depending on the 290 // value of |pop_out_actions_to_run|. 291 void ReorderActions(); 292 293 // Shows an extension message bubble, if any should be shown. 294 void MaybeShowExtensionBubble(); 295 296 // Returns the main bar, which is |main_bar_| if this is in overflow mode, and 297 // |this| otherwise. 298 ToolbarActionsBar* GetMainBar(); 299 300 // The delegate for this object (in a real build, this is the view). 301 ToolbarActionsBarDelegate* delegate_; 302 303 // The associated browser. 304 Browser* const browser_; 305 306 // The observed toolbar model. 307 ToolbarActionsModel* model_; 308 309 // The controller for the main toolbar actions bar. This will be null if this 310 // is the main bar. 311 ToolbarActionsBar* main_bar_; 312 313 // Platform-specific settings for dimensions. 314 PlatformSettings platform_settings_; 315 316 // The toolbar actions. 317 ToolbarActions toolbar_actions_; 318 319 // The action that triggered the current popup (just a reference to an action 320 // from toolbar_actions_). 321 ToolbarActionViewController* popup_owner_; 322 323 ScopedObserver<ToolbarActionsModel, ToolbarActionsModel::Observer> 324 model_observer_; 325 326 // True if we should suppress layout, such as when we are creating or 327 // adjusting a lot of actions at once. 328 bool suppress_layout_; 329 330 // True if we should suppress animation; we do this when first creating the 331 // toolbar, and also when switching tabs changes the state of the icons. 332 bool suppress_animation_; 333 334 // If this is true, actions that want to run (e.g., an extension's page 335 // action) will pop out of overflow to draw more attention. 336 // See also TabOrderHelper in the .cc file. 337 static bool pop_out_actions_to_run_; 338 339 // True if we should check to see if there is an extension bubble that should 340 // be displayed, and, if there is, started the process for showing that 341 // bubble. This is only ever true for the main bar. 342 bool should_check_extension_bubble_; 343 344 // The action, if any, which is currently "popped out" of the overflow in 345 // order to show a popup. 346 ToolbarActionViewController* popped_out_action_; 347 348 // True if the popped out action is "sticky", meaning it will stay popped 349 // out even if another menu is opened. 350 bool is_popped_out_sticky_; 351 352 // The task to alert the |popped_out_action_| that animation has finished, and 353 // it is fully popped out. 354 base::Closure popped_out_closure_; 355 356 // The controller for the toolbar action bubble to show once animation 357 // finishes, if any. 358 std::unique_ptr<ToolbarActionsBarBubbleDelegate> pending_bubble_controller_; 359 360 // True if a bubble is currently being shown. 361 bool is_showing_bubble_; 362 363 // The index of the action currently being dragged, or |base::nullopt| if 364 // no drag is in progress. 365 base::Optional<size_t> index_of_dragged_item_; 366 367 base::ObserverList<ToolbarActionsBarObserver>::Unchecked observers_; 368 369 base::WeakPtrFactory<ToolbarActionsBar> weak_ptr_factory_{this}; 370 371 DISALLOW_COPY_AND_ASSIGN(ToolbarActionsBar); 372 }; 373 374 #endif // CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_BAR_H_ 375