blob: befd13b2714dfbf9368e273bb8eef5fd7c8e2771 [file] [log] [blame]
// Copyright (c) 2012 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_TABS_TAB_STRIP_MODEL_IMPL_H_
#define CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_IMPL_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "ui/base/models/list_selection_model.h"
#include "ui/base/page_transition_types.h"
class Profile;
class TabStripModelDelegate;
class TabStripModelOrderController;
namespace content {
class WebContents;
}
// Normal implementation of the TabStripModel interface.
class TabStripModelImpl : public TabStripModel {
public:
// Construct a TabStripModel with a delegate to help it do certain things
// (see the TabStripModelDelegate documentation). |delegate| cannot be NULL.
TabStripModelImpl(TabStripModelDelegate* delegate, Profile* profile);
~TabStripModelImpl() override;
// TabStripModel implementation.
TabStripModelExperimental* AsTabStripModelExperimental() override;
TabStripModelDelegate* delegate() const override;
void AddObserver(TabStripModelObserver* observer) override;
void RemoveObserver(TabStripModelObserver* observer) override;
int count() const override;
bool empty() const override;
Profile* profile() const override;
int active_index() const override;
bool closing_all() const override;
bool ContainsIndex(int index) const override;
void AppendWebContents(content::WebContents* contents,
bool foreground) override;
void InsertWebContentsAt(int index,
content::WebContents* contents,
int add_types) override;
bool CloseWebContentsAt(int index, uint32_t close_types) override;
content::WebContents* ReplaceWebContentsAt(
int index,
content::WebContents* new_contents) override;
content::WebContents* DetachWebContentsAt(int index) override;
void ActivateTabAt(int index, bool user_gesture) override;
void AddTabAtToSelection(int index) override;
void MoveWebContentsAt(int index,
int to_position,
bool select_after_move) override;
void MoveSelectedTabsTo(int index) override;
content::WebContents* GetActiveWebContents() const override;
content::WebContents* GetWebContentsAt(int index) const override;
int GetIndexOfWebContents(
const content::WebContents* contents) const override;
void UpdateWebContentsStateAt(
int index,
TabStripModelObserver::TabChangeType change_type) override;
void SetTabNeedsAttentionAt(int index, bool attention) override;
void CloseAllTabs() override;
bool TabsAreLoading() const override;
content::WebContents* GetOpenerOfWebContentsAt(int index) override;
void SetOpenerOfWebContentsAt(int index,
content::WebContents* opener) override;
int GetIndexOfLastWebContentsOpenedBy(const content::WebContents* opener,
int start_index) const override;
void TabNavigating(content::WebContents* contents,
ui::PageTransition transition) override;
void SetTabBlocked(int index, bool blocked) override;
void SetTabPinned(int index, bool pinned) override;
bool IsTabPinned(int index) const override;
bool IsTabBlocked(int index) const override;
int IndexOfFirstNonPinnedTab() const override;
void ExtendSelectionTo(int index) override;
void ToggleSelectionAt(int index) override;
void AddSelectionFromAnchorTo(int index) override;
bool IsTabSelected(int index) const override;
void SetSelectionFromModel(ui::ListSelectionModel source) override;
const ui::ListSelectionModel& selection_model() const override;
void AddWebContents(content::WebContents* contents,
int index,
ui::PageTransition transition,
int add_types) override;
void CloseSelectedTabs() override;
void SelectNextTab() override;
void SelectPreviousTab() override;
void SelectLastTab() override;
void MoveTabNext() override;
void MoveTabPrevious() override;
bool IsContextMenuCommandEnabled(
int context_index,
ContextMenuCommand command_id) const override;
void ExecuteContextMenuCommand(int context_index,
ContextMenuCommand command_id) override;
std::vector<int> GetIndicesClosedByCommand(int index, ContextMenuCommand id)
const override;
bool WillContextMenuMute(int index) override;
bool WillContextMenuMuteSites(int index) override;
bool WillContextMenuPin(int index) override;
//////////////////////////////////////////////////////////////////////////////
// Ordering API
//
// These functions are used only by the TabStripModelOrderController which
// goes with this class (not the abstract base-class) so these do not need
// to be exposed in the general TabStripModel interface.
// Access the order controller. Exposed only for unit tests.
TabStripModelOrderController* order_controller() const {
return order_controller_.get();
}
// Returns the index of the next WebContents in the sequence of WebContentses
// spawned by the specified WebContents after |start_index|. If |use_group| is
// true, the group property of the tab is used instead of the opener to find
// the next tab. Under some circumstances the group relationship may exist but
// the opener may not.
int GetIndexOfNextWebContentsOpenedBy(const content::WebContents* opener,
int start_index,
bool use_group) const;
// Forget all Opener relationships that are stored (but _not_ group
// relationships!) This is to reduce unpredictable tab switching behavior
// in complex session states. The exact circumstances under which this method
// is called are left up to the implementation of the selected
// TabStripModelOrderController.
void ForgetAllOpeners();
// Forgets the group affiliation of the specified WebContents. This
// should be called when a WebContents that is part of a logical group
// of tabs is moved to a new logical context by the user (e.g. by typing a new
// URL or selecting a bookmark). This also forgets the opener, which is
// considered a weaker relationship than group.
void ForgetGroup(content::WebContents* contents);
// Returns true if the group/opener relationships present for |contents|
// should be reset when _any_ selection change occurs in the model.
bool ShouldResetGroupOnSelect(content::WebContents* contents) const;
private:
class WebContentsData;
// Used when making selection notifications.
enum class Notify {
kDefault,
// The selection is changing from a user gesture.
kUserGesture,
};
int ConstrainInsertionIndex(int index, bool pinned_tab);
// Convenience for converting a vector of indices into a vector of
// WebContents.
std::vector<content::WebContents*> GetWebContentsFromIndices(
const std::vector<int>& indices) const;
// Gets the set of tab indices whose domain matches the tab at |index|.
void GetIndicesWithSameDomain(int index, std::vector<int>* indices);
// Gets the set of tab indices that have the same opener as the tab at
// |index|.
void GetIndicesWithSameOpener(int index, std::vector<int>* indices);
// If |index| is selected all the selected indices are returned, otherwise a
// vector with |index| is returned. This is used when executing commands to
// determine which indices the command applies to.
std::vector<int> GetIndicesForCommand(int index) const;
// Returns true if the specified WebContents is a New Tab at the end of
// the tabstrip. We check for this because opener relationships are _not_
// forgotten for the New Tab page opened as a result of a New Tab gesture
// (e.g. Ctrl+T, etc) since the user may open a tab transiently to look up
// something related to their current activity.
bool IsNewTabAtEndOfTabStrip(content::WebContents* contents) const;
// Closes the WebContentses at the specified indices. This causes the
// WebContentses to be destroyed, but it may not happen immediately. If
// the page in question has an unload event the WebContents will not be
// destroyed until after the event has completed, which will then call back
// into this method.
//
// Returns true if the WebContentses were closed immediately, false if we
// are waiting for the result of an onunload handler.
bool InternalCloseTabs(const std::vector<int>& indices, uint32_t close_types);
// Invoked from InternalCloseTabs and when an extension is removed for an app
// tab. Notifies observers of TabClosingAt and deletes |contents|. If
// |create_historical_tabs| is true, CreateHistoricalTab is invoked on the
// delegate.
//
// The boolean parameter create_historical_tab controls whether to
// record these tabs and their history for reopening recently closed
// tabs.
void InternalCloseTab(content::WebContents* contents,
int index,
bool create_historical_tabs);
// Gets the WebContents at an index. Does no bounds checking.
content::WebContents* GetWebContentsAtImpl(int index) const;
// Notifies the observers if the active tab is being deactivated.
void NotifyIfTabDeactivated(content::WebContents* contents);
// Notifies the observers if the active tab has changed.
void NotifyIfActiveTabChanged(content::WebContents* old_contents,
Notify notify_types);
// Notifies the observers if the active tab or the tab selection has changed.
// |old_model| is a snapshot of |selection_model_| before the change.
// Note: This function might end up sending 0 to 2 notifications in the
// following order: ActiveTabChanged, TabSelectionChanged.
void NotifyIfActiveOrSelectionChanged(
content::WebContents* old_contents,
Notify notify_types,
const ui::ListSelectionModel& old_model);
// Sets the selection to |new_model| and notifies any observers.
// Note: This function might end up sending 0 to 3 notifications in the
// following order: TabDeactivated, ActiveTabChanged, TabSelectionChanged.
void SetSelection(ui::ListSelectionModel new_model, Notify notify_types);
// Selects either the next tab (|forward| is true), or the previous tab
// (|forward| is false).
void SelectRelativeTab(bool forward);
// Does the work of MoveWebContentsAt. This has no checks to make sure the
// position is valid, those are done in MoveWebContentsAt.
void MoveWebContentsAtImpl(int index,
int to_position,
bool select_after_move);
// Implementation of MoveSelectedTabsTo. Moves |length| of the selected tabs
// starting at |start| to |index|. See MoveSelectedTabsTo for more details.
void MoveSelectedTabsToImpl(int index, size_t start, size_t length);
// Returns true if the tab represented by the specified data has an opener
// that matches the specified one. If |use_group| is true, then this will
// fall back to check the group relationship as well.
static bool OpenerMatches(const std::unique_ptr<WebContentsData>& data,
const content::WebContents* opener,
bool use_group);
// Sets the group/opener of any tabs that reference the tab at |index| to that
// tab's group/opener respectively.
void FixOpenersAndGroupsReferencing(int index);
// Our delegate.
TabStripModelDelegate* delegate_;
// The WebContents data currently hosted within this TabStripModel.
std::vector<std::unique_ptr<WebContentsData>> contents_data_;
// A profile associated with this TabStripModel.
Profile* profile_;
// True if all tabs are currently being closed via CloseAllTabs.
bool closing_all_ = false;
// An object that determines where new Tabs should be inserted and where
// selection should move when a Tab is closed.
std::unique_ptr<TabStripModelOrderController> order_controller_;
// Our observers.
base::ObserverList<TabStripModelObserver> observers_;
ui::ListSelectionModel selection_model_;
// Indicates if observers are currently being notified to catch reentrancy
// bugs. See for example http://crbug.com/529407
bool in_notify_ = false;
base::WeakPtrFactory<TabStripModelImpl> weak_factory_;
DISALLOW_IMPLICIT_CONSTRUCTORS(TabStripModelImpl);
};
#endif // CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_IMPL_H_