| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_BAR_H_ |
| #define CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_BAR_H_ |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "base/callback.h" |
| #include "base/macros.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/observer_list.h" |
| #include "base/optional.h" |
| #include "base/scoped_observer.h" |
| #include "chrome/browser/ui/extensions/extensions_container.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" |
| #include "chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h" |
| #include "chrome/browser/ui/toolbar/toolbar_actions_model.h" |
| #include "ui/gfx/animation/tween.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace user_prefs { |
| class PrefRegistrySyncable; |
| } |
| |
| class ToolbarActionsBarDelegate; |
| class ToolbarActionsBarObserver; |
| class ToolbarActionViewController; |
| |
| // A platform-independent version of the container for toolbar actions, |
| // including extension actions and component actions. |
| // |
| // This is a per-window instance, unlike the ToolbarActionsModel, which is |
| // per-profile. In most cases, ordering and visible count will be identical |
| // between the base model and the window; however, there are exceptions in the |
| // case of very small windows (which may be too narrow to display all the |
| // icons), or windows in which an action is "popped out", resulting in a |
| // re-ordering. |
| // |
| // This can come in two flavors, main and "overflow". The main bar is visible |
| // next to the omnibox, and the overflow bar is visible inside the chrome |
| // app menu. The main bar can have only a single row of icons with flexible |
| // width, whereas the overflow bar has multiple rows of icons with a fixed |
| // width (the width of the menu). |
| class ToolbarActionsBar : public ExtensionsContainer, |
| public ToolbarActionsModel::Observer, |
| public TabStripModelObserver { |
| public: |
| using ToolbarActions = |
| std::vector<std::unique_ptr<ToolbarActionViewController>>; |
| |
| // A struct to contain the platform settings. |
| struct PlatformSettings { |
| PlatformSettings(); |
| |
| // The spacing between each of the icons, between the start of the |
| // container and the first item, and between the last item and end of |
| // the container. |
| int item_spacing; |
| // The number of icons per row in the overflow menu. |
| int icons_per_overflow_menu_row; |
| }; |
| |
| // The type of drag that occurred in a drag-and-drop operation. |
| enum DragType { |
| // The icon was dragged to the same container it started in. |
| DRAG_TO_SAME, |
| // The icon was dragged from the main container to the overflow. |
| DRAG_TO_OVERFLOW, |
| // The icon was dragged from the overflow container to the main. |
| DRAG_TO_MAIN, |
| }; |
| |
| enum HighlightType { |
| HIGHLIGHT_NONE, |
| HIGHLIGHT_WARNING, |
| }; |
| |
| ToolbarActionsBar(ToolbarActionsBarDelegate* delegate, |
| Browser* browser, |
| ToolbarActionsBar* main_bar); |
| ~ToolbarActionsBar() override; |
| |
| // Registers profile preferences. |
| static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); |
| |
| // Returns the size of the area where the action icon resides. |
| static gfx::Size GetIconAreaSize(); |
| |
| // Returns the size of ToolbarActionView. |
| gfx::Size GetViewSize() const; |
| |
| // Returns the default/full size for the toolbar; this does *not* reflect any |
| // animations that may be running. |
| gfx::Size GetFullSize() const; |
| |
| // Returns the [minimum|maximum] possible width for the toolbar. |
| virtual int GetMinimumWidth() const; |
| int GetMaximumWidth() const; |
| |
| // Returns the width for the given number of icons. |
| int IconCountToWidth(size_t icons) const; |
| |
| // Returns the number of icons that can fit within the given width. |
| size_t WidthToIconCount(int width) const; |
| |
| // Returns the number of icons that should be displayed if space allows. Can |
| // be overridden by children to impose a smaller limit on the number of icons. |
| virtual size_t GetIconCount() const; |
| |
| // Returns the starting index (inclusive) for displayable icons. |
| size_t GetStartIndexInBounds() const; |
| |
| // Returns the ending index (exclusive) for displayable icons. |
| size_t GetEndIndexInBounds() const; |
| |
| // Returns true if an overflow container is necessary to display any other |
| // icons for this particular window. This is different than |
| // ToolbarActionsModel::all_icons_visible() because the ToolbarActionsBar |
| // is limited to a single window, whereas the model is the underlying model |
| // of *all* windows, independent of size. As such, the model is identical |
| // between a very wide window and a very narrow window, and the user's stored |
| // preference may be to have all icons visible. But if the very narrow window |
| // doesn't have the width to display all those actions, some will need to be |
| // implicitly pushed to the overflow, even though the user's global preference |
| // has not changed. |
| bool NeedsOverflow() const; |
| |
| // Returns the frame (bounds) that the specified index should have, taking |
| // into account if this is the main or overflow bar. If this is the overflow |
| // bar and the index should not be displayed (i.e., it is shown on the main |
| // bar), returns an empty rect. |
| gfx::Rect GetFrameForIndex(size_t index) const; |
| |
| // Returns the actions in the proper order; this may differ from the |
| // underlying order in the case of actions being popped out to show a popup. |
| std::vector<ToolbarActionViewController*> GetActions() const; |
| |
| // Creates the toolbar actions. |
| void CreateActions(); |
| |
| // Deletes all toolbar actions. |
| void DeleteActions(); |
| |
| // Updates all the toolbar actions. |
| void Update(); |
| |
| // Shows the popup for the action with |id|, returning true if a popup is |
| // shown. If |grant_active_tab| is true, then active tab permissions should |
| // be given to the action (only do this if this is through a user action). |
| bool ShowToolbarActionPopup(const std::string& id, bool grant_active_tab); |
| |
| // Sets the width for the overflow menu rows. |
| void SetOverflowRowWidth(int width); |
| |
| // Notifies the ToolbarActionsBar that a user completed a resize gesture, and |
| // the new width is |width|. |
| void OnResizeComplete(int width); |
| |
| // Notifies the ToolbarActionsBar that the user has started dragging the |
| // action at index |index_of_dragged_item|. |
| void OnDragStarted(size_t index_of_dragged_item); |
| |
| // Notifies the ToolbarActionsBar that a drag-and-drop sequence ended. This |
| // may not coincide with OnDragDrop(), since the view may be dropped somewhere |
| // else. |
| void OnDragEnded(); |
| |
| // Notifies the ToolbarActionsBar that a user completed a drag and drop event, |
| // and dragged the view from |dragged_index| to |dropped_index|. |
| // |drag_type| indicates whether or not the icon was dragged between the |
| // overflow and main containers. |
| // The main container should handle all drag/drop notifications. |
| void OnDragDrop(int dragged_index, |
| int dropped_index, |
| DragType drag_type); |
| |
| // The index of the action currently being dragged, or |base::nullopt| if |
| // no drag is in progress. Should only be called on the main bar. |
| const base::Optional<size_t> IndexOfDraggedItem() const; |
| |
| // Notifies the ToolbarActionsBar that the delegate finished animating. |
| void OnAnimationEnded(); |
| |
| // Called when the active bubble is closed. |
| void OnBubbleClosed(); |
| |
| // Add or remove an observer. |
| void AddObserver(ToolbarActionsBarObserver* observer); |
| void RemoveObserver(ToolbarActionsBarObserver* observer); |
| |
| // Displays the given |bubble| once the toolbar is no longer animating. |
| void ShowToolbarActionBubble( |
| std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble); |
| // Same as above, but uses PostTask() in all cases. |
| void ShowToolbarActionBubbleAsync( |
| std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble); |
| |
| // Returns the underlying toolbar actions, but does not order them. Primarily |
| // for use in testing. |
| const ToolbarActions& toolbar_actions_unordered() const { |
| return toolbar_actions_; |
| } |
| bool enabled() const { return model_ != nullptr; } |
| bool suppress_layout() const { return suppress_layout_; } |
| bool suppress_animation() const { |
| return suppress_animation_ || disable_animations_for_testing_; |
| } |
| bool is_highlighting() const { return model_ && model_->is_highlighting(); } |
| ToolbarActionsModel::HighlightType highlight_type() const { |
| return model_ ? model_->highlight_type() |
| : ToolbarActionsModel::HIGHLIGHT_NONE; |
| } |
| const PlatformSettings& platform_settings() const { |
| return platform_settings_; |
| } |
| ToolbarActionViewController* popup_owner() { return popup_owner_; } |
| bool in_overflow_mode() const { return main_bar_ != nullptr; } |
| bool is_showing_bubble() const { return is_showing_bubble_; } |
| |
| bool is_drag_in_progress() const { |
| return index_of_dragged_item_ != base::nullopt; |
| } |
| |
| ToolbarActionsBarDelegate* delegate_for_test() { return delegate_; } |
| |
| // During testing we can disable animations by setting this flag to true, |
| // so that the bar resizes instantly, instead of having to poll it while it |
| // animates to open/closed status. |
| static bool disable_animations_for_testing_; |
| static void set_extension_bubble_appearance_wait_time_for_testing( |
| int time_in_seconds); |
| |
| // ExtensionsContainer: |
| ToolbarActionViewController* GetActionForId( |
| const std::string& action_id) override; |
| ToolbarActionViewController* GetPoppedOutAction() const override; |
| bool IsActionVisibleOnToolbar( |
| const ToolbarActionViewController* action) const override; |
| void UndoPopOut() override; |
| void SetPopupOwner(ToolbarActionViewController* popup_owner) override; |
| void HideActivePopup() override; |
| bool CloseOverflowMenuIfOpen() override; |
| void PopOutAction(ToolbarActionViewController* action, |
| bool is_sticky, |
| const base::Closure& closure) override; |
| |
| private: |
| // Returns the insets by which the icon area bounds (See GetIconAreaRect()) |
| // are insetted. This defines the amount of paddings around the icon area. |
| virtual gfx::Insets GetIconAreaInsets() const; |
| |
| // Returns the number of icons that can fit within the given width. |
| size_t WidthToIconCountUnclamped(int width) const; |
| |
| // ToolbarActionsModel::Observer: |
| void OnToolbarActionAdded(const ToolbarActionsModel::ActionId& action_id, |
| int index) override; |
| void OnToolbarActionRemoved( |
| const ToolbarActionsModel::ActionId& action_id) override; |
| void OnToolbarActionMoved(const ToolbarActionsModel::ActionId& action_id, |
| int index) override; |
| void OnToolbarActionLoadFailed() override; |
| void OnToolbarActionUpdated( |
| const ToolbarActionsModel::ActionId& action_id) override; |
| void OnToolbarVisibleCountChanged() override; |
| void OnToolbarHighlightModeChanged(bool is_highlighting) override; |
| void OnToolbarModelInitialized() override; |
| |
| // TabStripModelObserver: |
| void OnTabStripModelChanged( |
| TabStripModel* tab_strip_model, |
| const TabStripModelChange& change, |
| const TabStripSelectionChange& selection) override; |
| |
| // Resizes the delegate (if necessary) to the preferred size using the given |
| // |tween_type|. |
| void ResizeDelegate(gfx::Tween::Type tween_type); |
| |
| // Returns the current web contents. |
| content::WebContents* GetCurrentWebContents(); |
| |
| // Reorders the toolbar actions to reflect the model and, optionally, to |
| // "pop out" any overflowed actions that want to run (depending on the |
| // value of |pop_out_actions_to_run|. |
| void ReorderActions(); |
| |
| // Shows an extension message bubble, if any should be shown. |
| void MaybeShowExtensionBubble(); |
| |
| // Returns the main bar, which is |main_bar_| if this is in overflow mode, and |
| // |this| otherwise. |
| ToolbarActionsBar* GetMainBar(); |
| |
| // The delegate for this object (in a real build, this is the view). |
| ToolbarActionsBarDelegate* delegate_; |
| |
| // The associated browser. |
| Browser* const browser_; |
| |
| // The observed toolbar model. |
| ToolbarActionsModel* model_; |
| |
| // The controller for the main toolbar actions bar. This will be null if this |
| // is the main bar. |
| ToolbarActionsBar* main_bar_; |
| |
| // Platform-specific settings for dimensions. |
| PlatformSettings platform_settings_; |
| |
| // The toolbar actions. |
| ToolbarActions toolbar_actions_; |
| |
| // The action that triggered the current popup (just a reference to an action |
| // from toolbar_actions_). |
| ToolbarActionViewController* popup_owner_; |
| |
| ScopedObserver<ToolbarActionsModel, ToolbarActionsModel::Observer> |
| model_observer_; |
| |
| // True if we should suppress layout, such as when we are creating or |
| // adjusting a lot of actions at once. |
| bool suppress_layout_; |
| |
| // True if we should suppress animation; we do this when first creating the |
| // toolbar, and also when switching tabs changes the state of the icons. |
| bool suppress_animation_; |
| |
| // If this is true, actions that want to run (e.g., an extension's page |
| // action) will pop out of overflow to draw more attention. |
| // See also TabOrderHelper in the .cc file. |
| static bool pop_out_actions_to_run_; |
| |
| // True if we should check to see if there is an extension bubble that should |
| // be displayed, and, if there is, started the process for showing that |
| // bubble. This is only ever true for the main bar. |
| bool should_check_extension_bubble_; |
| |
| // The action, if any, which is currently "popped out" of the overflow in |
| // order to show a popup. |
| ToolbarActionViewController* popped_out_action_; |
| |
| // True if the popped out action is "sticky", meaning it will stay popped |
| // out even if another menu is opened. |
| bool is_popped_out_sticky_; |
| |
| // The task to alert the |popped_out_action_| that animation has finished, and |
| // it is fully popped out. |
| base::Closure popped_out_closure_; |
| |
| // The controller for the toolbar action bubble to show once animation |
| // finishes, if any. |
| std::unique_ptr<ToolbarActionsBarBubbleDelegate> pending_bubble_controller_; |
| |
| // True if a bubble is currently being shown. |
| bool is_showing_bubble_; |
| |
| // The index of the action currently being dragged, or |base::nullopt| if |
| // no drag is in progress. |
| base::Optional<size_t> index_of_dragged_item_; |
| |
| ScopedObserver<TabStripModel, TabStripModelObserver> tab_strip_observer_; |
| |
| base::ObserverList<ToolbarActionsBarObserver>::Unchecked observers_; |
| |
| base::WeakPtrFactory<ToolbarActionsBar> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ToolbarActionsBar); |
| }; |
| |
| #endif // CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTIONS_BAR_H_ |