Home | History | Annotate | Download | only in tabs
      1 // Copyright (c) 2011 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_TABS_TAB_STRIP_MODEL_H_
      6 #define CHROME_BROWSER_TABS_TAB_STRIP_MODEL_H_
      7 #pragma once
      8 
      9 #include <vector>
     10 
     11 #include "base/observer_list.h"
     12 #include "chrome/browser/tabs/tab_strip_model_observer.h"
     13 #include "chrome/browser/tabs/tab_strip_selection_model.h"
     14 #include "content/common/notification_observer.h"
     15 #include "content/common/notification_registrar.h"
     16 #include "content/common/page_transition_types.h"
     17 
     18 class NavigationController;
     19 class Profile;
     20 class TabContents;
     21 class TabContentsWrapper;
     22 class TabStripModelDelegate;
     23 class TabStripModelOrderController;
     24 
     25 ////////////////////////////////////////////////////////////////////////////////
     26 //
     27 // TabStripModel
     28 //
     29 //  A model & low level controller of a Browser Window tabstrip. Holds a vector
     30 //  of TabContents, and provides an API for adding, removing and shuffling
     31 //  them, as well as a higher level API for doing specific Browser-related
     32 //  tasks like adding new Tabs from just a URL, etc.
     33 //
     34 // Each tab may be any one of the following states:
     35 // . Mini-tab. Mini tabs are locked to the left side of the tab strip and
     36 //   rendered differently (small tabs with only a favicon). The model makes
     37 //   sure all mini-tabs are at the beginning of the tab strip. For example,
     38 //   if a non-mini tab is added it is forced to be with non-mini tabs. Requests
     39 //   to move tabs outside the range of the tab type are ignored. For example,
     40 //   a request to move a mini-tab after non-mini-tabs is ignored.
     41 //   You'll notice there is no explcit api for making a tab a mini-tab, rather
     42 //   there are two tab types that are implicitly mini-tabs:
     43 //   . App. Corresponds to an extension that wants an app tab. App tabs are
     44 //     identified by TabContentsWrapper::extension_tab_helper()::is_app().
     45 //     App tabs are always pinneded (you can't unpin them).
     46 //   . Pinned. Any tab can be pinned. Non-app tabs whose pinned state is changed
     47 //     are moved to be with other mini-tabs or non-mini tabs.
     48 //
     49 //  A TabStripModel has one delegate that it relies on to perform certain tasks
     50 //  like creating new TabStripModels (probably hosted in Browser windows) when
     51 //  required. See TabStripDelegate above for more information.
     52 //
     53 //  A TabStripModel also has N observers (see TabStripModelObserver above),
     54 //  which can be registered via Add/RemoveObserver. An Observer is notified of
     55 //  tab creations, removals, moves, and other interesting events. The
     56 //  TabStrip implements this interface to know when to create new tabs in
     57 //  the View, and the Browser object likewise implements to be able to update
     58 //  its bookkeeping when such events happen.
     59 //
     60 ////////////////////////////////////////////////////////////////////////////////
     61 class TabStripModel : public NotificationObserver {
     62  public:
     63   // Policy for how new tabs are inserted.
     64   enum InsertionPolicy {
     65     // Newly created tabs are created after the selection. This is the default.
     66     INSERT_AFTER,
     67 
     68     // Newly created tabs are inserted before the selection.
     69     INSERT_BEFORE,
     70   };
     71 
     72   // Used to specify what should happen when the tab is closed.
     73   enum CloseTypes {
     74     CLOSE_NONE                     = 0,
     75 
     76     // Indicates the tab was closed by the user. If true,
     77     // TabContents::set_closed_by_user_gesture(true) is invoked.
     78     CLOSE_USER_GESTURE             = 1 << 0,
     79 
     80     // If true the history is recorded so that the tab can be reopened later.
     81     // You almost always want to set this.
     82     CLOSE_CREATE_HISTORICAL_TAB    = 1 << 1,
     83   };
     84 
     85   // Constants used when adding tabs.
     86   enum AddTabTypes {
     87     // Used to indicate nothing special should happen to the newly inserted
     88     // tab.
     89     ADD_NONE          = 0,
     90 
     91     // The tab should be active.
     92     ADD_ACTIVE        = 1 << 0,
     93 
     94     // The tab should be pinned.
     95     ADD_PINNED        = 1 << 1,
     96 
     97     // If not set the insertion index of the TabContents is left up to the Order
     98     // Controller associated, so the final insertion index may differ from the
     99     // specified index. Otherwise the index supplied is used.
    100     ADD_FORCE_INDEX   = 1 << 2,
    101 
    102     // If set the newly inserted tab inherits the group of the currently
    103     // selected tab. If not set the tab may still inherit the group under
    104     // certain situations.
    105     ADD_INHERIT_GROUP = 1 << 3,
    106 
    107     // If set the newly inserted tab's opener is set to the active tab. If not
    108     // set the tab may still inherit the group/opener under certain situations.
    109     // NOTE: this is ignored if ADD_INHERIT_GROUP is set.
    110     ADD_INHERIT_OPENER = 1 << 4,
    111   };
    112 
    113   static const int kNoTab = -1;
    114 
    115   // Construct a TabStripModel with a delegate to help it do certain things
    116   // (See TabStripModelDelegate documentation). |delegate| cannot be NULL.
    117   TabStripModel(TabStripModelDelegate* delegate, Profile* profile);
    118   virtual ~TabStripModel();
    119 
    120   // Retrieves the TabStripModelDelegate associated with this TabStripModel.
    121   TabStripModelDelegate* delegate() const { return delegate_; }
    122 
    123   // Add and remove observers to changes within this TabStripModel.
    124   void AddObserver(TabStripModelObserver* observer);
    125   void RemoveObserver(TabStripModelObserver* observer);
    126 
    127   // Retrieve the number of TabContentses/emptiness of the TabStripModel.
    128   int count() const { return static_cast<int>(contents_data_.size()); }
    129   bool empty() const { return contents_data_.empty(); }
    130 
    131   // Retrieve the Profile associated with this TabStripModel.
    132   Profile* profile() const { return profile_; }
    133 
    134   // Retrieve the index of the currently active TabContents.
    135   int active_index() const { return selection_model_.active(); }
    136 
    137   // Returns true if the tabstrip is currently closing all open tabs (via a
    138   // call to CloseAllTabs). As tabs close, the selection in the tabstrip
    139   // changes which notifies observers, which can use this as an optimization to
    140   // avoid doing meaningless or unhelpful work.
    141   bool closing_all() const { return closing_all_; }
    142 
    143   // Access the order controller. Exposed only for unit tests.
    144   TabStripModelOrderController* order_controller() const {
    145     return order_controller_;
    146   }
    147 
    148   // Sets the insertion policy. Default is INSERT_AFTER.
    149   void SetInsertionPolicy(InsertionPolicy policy);
    150   InsertionPolicy insertion_policy() const;
    151 
    152   // Returns true if |observer| is in the list of observers. This is intended
    153   // for debugging.
    154   bool HasObserver(TabStripModelObserver* observer);
    155 
    156   // Basic API /////////////////////////////////////////////////////////////////
    157 
    158   // Determines if the specified index is contained within the TabStripModel.
    159   bool ContainsIndex(int index) const;
    160 
    161   // Adds the specified TabContents in the default location. Tabs opened in the
    162   // foreground inherit the group of the previously active tab.
    163   void AppendTabContents(TabContentsWrapper* contents, bool foreground);
    164 
    165   // Adds the specified TabContents at the specified location. |add_types| is a
    166   // bitmask of AddTypes; see it for details.
    167   //
    168   // All append/insert methods end up in this method.
    169   //
    170   // NOTE: adding a tab using this method does NOT query the order controller,
    171   // as such the ADD_FORCE_INDEX AddType is meaningless here.  The only time the
    172   // |index| is changed is if using the index would result in breaking the
    173   // constraint that all mini-tabs occur before non-mini-tabs.
    174   // See also AddTabContents.
    175   void InsertTabContentsAt(int index,
    176                            TabContentsWrapper* contents,
    177                            int add_types);
    178 
    179   // Closes the TabContents at the specified index. This causes the TabContents
    180   // to be destroyed, but it may not happen immediately (e.g. if it's a
    181   // TabContents). |close_types| is a bitmask of CloseTypes.
    182   // Returns true if the TabContents was closed immediately, false if it was not
    183   // closed (we may be waiting for a response from an onunload handler, or
    184   // waiting for the user to confirm closure).
    185   bool CloseTabContentsAt(int index, uint32 close_types);
    186 
    187   // Replaces the entire state of a the tab at index by switching in a
    188   // different NavigationController. This is used through the recently
    189   // closed tabs list, which needs to replace a tab's current state
    190   // and history with another set of contents and history.
    191   //
    192   // The old NavigationController is deallocated and this object takes
    193   // ownership of the passed in controller.
    194   // XXXPINK This API is weird and wrong. Remove it or change it or rename it?
    195   void ReplaceNavigationControllerAt(int index,
    196                                      TabContentsWrapper* contents);
    197 
    198   // Replaces the tab contents at |index| with |new_contents|. The
    199   // TabContentsWrapper that was at |index| is returned and ownership returns
    200   // to the caller.
    201   TabContentsWrapper* ReplaceTabContentsAt(int index,
    202                                            TabContentsWrapper* new_contents);
    203 
    204   // Detaches the TabContents at the specified index from this strip. The
    205   // TabContents is not destroyed, just removed from display. The caller is
    206   // responsible for doing something with it (e.g. stuffing it into another
    207   // strip).
    208   TabContentsWrapper* DetachTabContentsAt(int index);
    209 
    210   // Makes the tab at the specified index the active tab. |user_gesture| is true
    211   // if the user actually clicked on the tab or navigated to it using a keyboard
    212   // command, false if the tab was activated as a by-product of some other
    213   // action.
    214   void ActivateTabAt(int index, bool user_gesture);
    215 
    216   // Move the TabContents at the specified index to another index. This method
    217   // does NOT send Detached/Attached notifications, rather it moves the
    218   // TabContents inline and sends a Moved notification instead.
    219   // If |select_after_move| is false, whatever tab was selected before the move
    220   // will still be selected, but it's index may have incremented or decremented
    221   // one slot.
    222   // NOTE: this does nothing if the move would result in app tabs and non-app
    223   // tabs mixing.
    224   void MoveTabContentsAt(int index, int to_position, bool select_after_move);
    225 
    226   // Moves the selected tabs to |index|. |index| is treated as if the tab strip
    227   // did not contain any of the selected tabs. For example, if the tabstrip
    228   // contains [A b c D E f] (upper case selected) and this is invoked with 1 the
    229   // result is [b A D E c f].
    230   // This method maintains that all mini-tabs occur before non-mini-tabs.  When
    231   // mini-tabs are selected the move is processed in two chunks: first mini-tabs
    232   // are moved, then non-mini-tabs are moved. If the index is after
    233   // (mini-tab-count - selected-mini-tab-count), then the index the non-mini
    234   // selected tabs are moved to is (index + selected-mini-tab-count). For
    235   // example, if the model consists of [A b c D E f] (A b c are mini) and this
    236   // is inokved with 2, the result is [b c A D E f]. In this example nothing
    237   // special happened because the target index was <= (mini-tab-count -
    238   // selected-mini-tab-count). If the target index were 3, then the result would
    239   // be [b c A f D F]. A, being mini, can move no further than index 2. The
    240   // non-mini-tabs are moved to the target index + selected-mini-tab-count (3 +
    241   // 1)
    242   void MoveSelectedTabsTo(int index);
    243 
    244   // Returns the currently selected TabContents, or NULL if there is none.
    245   // TODO(sky): rename to GetActiveTabContents.
    246   TabContentsWrapper* GetSelectedTabContents() const;
    247 
    248   // Returns the TabContentsWrapper at the specified index, or NULL if there is
    249   // none.
    250   TabContentsWrapper* GetTabContentsAt(int index) const;
    251 
    252   // Returns the index of the specified TabContents wrapper, or
    253   // TabStripModel::kNoTab if the TabContents is not in this TabStripModel.
    254   int GetIndexOfTabContents(const TabContentsWrapper* contents) const;
    255 
    256   // Returns the index of the specified TabContents wrapper given its raw
    257   // TabContents, or TabStripModel::kNoTab if the TabContents is not in this
    258   // TabStripModel.  Note: This is only needed in rare cases where the wrapper
    259   // is not already present (such as implementing TabContentsDelegate methods,
    260   // which don't know about the wrapper.  Returns NULL if |contents| is not
    261   // associated with any wrapper in the model.
    262   int GetWrapperIndex(const TabContents* contents) const;
    263 
    264   // Returns the index of the specified NavigationController, or kNoTab if it is
    265   // not in this TabStripModel.
    266   int GetIndexOfController(const NavigationController* controller) const;
    267 
    268   // Notify any observers that the TabContents at the specified index has
    269   // changed in some way. See TabChangeType for details of |change_type|.
    270   void UpdateTabContentsStateAt(
    271       int index,
    272       TabStripModelObserver::TabChangeType change_type);
    273 
    274   // Make sure there is an auto-generated New Tab tab in the TabStripModel.
    275   // If |force_create| is true, the New Tab will be created even if the
    276   // preference is set to false (used by startup).
    277   void EnsureNewTabVisible(bool force_create);
    278 
    279   // Close all tabs at once. Code can use closing_all() above to defer
    280   // operations that might otherwise by invoked by the flurry of detach/select
    281   // notifications this method causes.
    282   void CloseAllTabs();
    283 
    284   // Returns true if there are any TabContents that are currently loading.
    285   bool TabsAreLoading() const;
    286 
    287   // Returns the controller controller that opened the TabContents at |index|.
    288   NavigationController* GetOpenerOfTabContentsAt(int index);
    289 
    290   // Returns the index of the next TabContents in the sequence of TabContentses
    291   // spawned by the specified NavigationController after |start_index|.
    292   // If |use_group| is true, the group property of the tab is used instead of
    293   // the opener to find the next tab. Under some circumstances the group
    294   // relationship may exist but the opener may not.
    295   int GetIndexOfNextTabContentsOpenedBy(const NavigationController* opener,
    296                                         int start_index,
    297                                         bool use_group) const;
    298 
    299   // Returns the index of the first TabContents in the model opened by the
    300   // specified opener.
    301   int GetIndexOfFirstTabContentsOpenedBy(const NavigationController* opener,
    302                                          int start_index) const;
    303 
    304   // Returns the index of the last TabContents in the model opened by the
    305   // specified opener, starting at |start_index|.
    306   int GetIndexOfLastTabContentsOpenedBy(const NavigationController* opener,
    307                                         int start_index) const;
    308 
    309   // Called by the Browser when a navigation is about to occur in the specified
    310   // TabContents. Depending on the tab, and the transition type of the
    311   // navigation, the TabStripModel may adjust its selection and grouping
    312   // behavior.
    313   void TabNavigating(TabContentsWrapper* contents,
    314                      PageTransition::Type transition);
    315 
    316   // Forget all Opener relationships that are stored (but _not_ group
    317   // relationships!) This is to reduce unpredictable tab switching behavior
    318   // in complex session states. The exact circumstances under which this method
    319   // is called are left up to the implementation of the selected
    320   // TabStripModelOrderController.
    321   void ForgetAllOpeners();
    322 
    323   // Forgets the group affiliation of the specified TabContents. This should be
    324   // called when a TabContents that is part of a logical group of tabs is
    325   // moved to a new logical context by the user (e.g. by typing a new URL or
    326   // selecting a bookmark). This also forgets the opener, which is considered
    327   // a weaker relationship than group.
    328   void ForgetGroup(TabContentsWrapper* contents);
    329 
    330   // Returns true if the group/opener relationships present for |contents|
    331   // should be reset when _any_ selection change occurs in the model.
    332   bool ShouldResetGroupOnSelect(TabContentsWrapper* contents) const;
    333 
    334   // Changes the blocked state of the tab at |index|.
    335   void SetTabBlocked(int index, bool blocked);
    336 
    337   // Changes the pinned state of the tab at |index|. See description above
    338   // class for details on this.
    339   void SetTabPinned(int index, bool pinned);
    340 
    341   // Returns true if the tab at |index| is pinned.
    342   // See description above class for details on pinned tabs.
    343   bool IsTabPinned(int index) const;
    344 
    345   // Is the tab a mini-tab?
    346   // See description above class for details on this.
    347   bool IsMiniTab(int index) const;
    348 
    349   // Is the tab at |index| an app?
    350   // See description above class for details on app tabs.
    351   bool IsAppTab(int index) const;
    352 
    353   // Returns true if the tab at |index| is blocked by a tab modal dialog.
    354   bool IsTabBlocked(int index) const;
    355 
    356   // Returns the index of the first tab that is not a mini-tab. This returns
    357   // |count()| if all of the tabs are mini-tabs, and 0 if none of the tabs are
    358   // mini-tabs.
    359   int IndexOfFirstNonMiniTab() const;
    360 
    361   // Returns a valid index for inserting a new tab into this model. |index| is
    362   // the proposed index and |mini_tab| is true if inserting a tab will become
    363   // mini (pinned or app). If |mini_tab| is true, the returned index is between
    364   // 0 and IndexOfFirstNonMiniTab. If |mini_tab| is false, the returned index
    365   // is between IndexOfFirstNonMiniTab and count().
    366   int ConstrainInsertionIndex(int index, bool mini_tab);
    367 
    368   // Extends the selection from the anchor to |index|.
    369   void ExtendSelectionTo(int index);
    370 
    371   // Toggles the selection at |index|. This does nothing if |index| is selected
    372   // and there are no other selected tabs.
    373   void ToggleSelectionAt(int index);
    374 
    375   // Makes sure the tabs from the anchor to |index| are selected. This only
    376   // adds to the selection.
    377   void AddSelectionFromAnchorTo(int index);
    378 
    379   // Returns true if the tab at |index| is selected.
    380   bool IsTabSelected(int index) const;
    381 
    382   // Sets the selection to match that of |source|.
    383   void SetSelectionFromModel(const TabStripSelectionModel& source);
    384 
    385   const TabStripSelectionModel& selection_model() const {
    386     return selection_model_;
    387   }
    388 
    389   // Command level API /////////////////////////////////////////////////////////
    390 
    391   // Adds a TabContents at the best position in the TabStripModel given the
    392   // specified insertion index, transition, etc. |add_types| is a bitmask of
    393   // AddTypes; see it for details. This method ends up calling into
    394   // InsertTabContentsAt to do the actual inertion.
    395   void AddTabContents(TabContentsWrapper* contents,
    396                       int index,
    397                       PageTransition::Type transition,
    398                       int add_types);
    399 
    400   // Closes the selected tabs.
    401   void CloseSelectedTabs();
    402 
    403   // Select adjacent tabs
    404   void SelectNextTab();
    405   void SelectPreviousTab();
    406 
    407   // Selects the last tab in the tab strip.
    408   void SelectLastTab();
    409 
    410   // Swap adjacent tabs.
    411   void MoveTabNext();
    412   void MoveTabPrevious();
    413 
    414   // View API //////////////////////////////////////////////////////////////////
    415 
    416   // Context menu functions.
    417   enum ContextMenuCommand {
    418     CommandFirst = 0,
    419     CommandNewTab,
    420     CommandReload,
    421     CommandDuplicate,
    422     CommandCloseTab,
    423     CommandCloseOtherTabs,
    424     CommandCloseTabsToRight,
    425     CommandRestoreTab,
    426     CommandTogglePinned,
    427     CommandBookmarkAllTabs,
    428     CommandUseVerticalTabs,
    429     CommandSelectByDomain,
    430     CommandSelectByOpener,
    431     CommandLast
    432   };
    433 
    434   // Returns true if the specified command is enabled. If |context_index| is
    435   // selected the response applies to all selected tabs.
    436   bool IsContextMenuCommandEnabled(int context_index,
    437                                    ContextMenuCommand command_id) const;
    438 
    439   // Returns true if the specified command is checked.
    440   bool IsContextMenuCommandChecked(int context_index,
    441                                    ContextMenuCommand command_id) const;
    442 
    443   // Performs the action associated with the specified command for the given
    444   // TabStripModel index |context_index|.  If |context_index| is selected the
    445   // command applies to all selected tabs.
    446   void ExecuteContextMenuCommand(int context_index,
    447                                  ContextMenuCommand command_id);
    448 
    449   // Returns a vector of indices of the tabs that will close when executing the
    450   // command |id| for the tab at |index|. The returned indices are sorted in
    451   // descending order.
    452   std::vector<int> GetIndicesClosedByCommand(int index,
    453                                              ContextMenuCommand id) const;
    454 
    455   // Returns true if 'CommandTogglePinned' will pin. |index| is the index
    456   // supplied to |ExecuteContextMenuCommand|.
    457   bool WillContextMenuPin(int index);
    458 
    459   // Overridden from notificationObserver:
    460   virtual void Observe(NotificationType type,
    461                        const NotificationSource& source,
    462                        const NotificationDetails& details);
    463 
    464   // Convert a ContextMenuCommand into a browser command. Returns true if a
    465   // corresponding browser command exists, false otherwise.
    466   static bool ContextMenuCommandToBrowserCommand(int cmd_id, int* browser_cmd);
    467 
    468  private:
    469   // Gets the set of tab indices whose domain matches the tab at |index|.
    470   void GetIndicesWithSameDomain(int index, std::vector<int>* indices);
    471 
    472   // Gets the set of tab indices that have the same opener as the tab at
    473   // |index|.
    474   void GetIndicesWithSameOpener(int index, std::vector<int>* indices);
    475 
    476   // If |index| is selected all the selected indices are returned, otherwise a
    477   // vector with |index| is returned. This is used when executing commands to
    478   // determine which indices the command applies to.
    479   std::vector<int> GetIndicesForCommand(int index) const;
    480 
    481   // Returns true if the specified TabContents is a New Tab at the end of the
    482   // TabStrip. We check for this because opener relationships are _not_
    483   // forgotten for the New Tab page opened as a result of a New Tab gesture
    484   // (e.g. Ctrl+T, etc) since the user may open a tab transiently to look up
    485   // something related to their current activity.
    486   bool IsNewTabAtEndOfTabStrip(TabContentsWrapper* contents) const;
    487 
    488   // Closes the TabContents at the specified indices. This causes the
    489   // TabContents to be destroyed, but it may not happen immediately.  If the
    490   // page in question has an unload event the TabContents will not be destroyed
    491   // until after the event has completed, which will then call back into this
    492   // method.
    493   //
    494   // Returns true if the TabContents were closed immediately, false if we are
    495   // waiting for the result of an onunload handler.
    496   bool InternalCloseTabs(const std::vector<int>& indices, uint32 close_types);
    497 
    498   // Invoked from InternalCloseTabs and when an extension is removed for an app
    499   // tab. Notifies observers of TabClosingAt and deletes |contents|. If
    500   // |create_historical_tabs| is true, CreateHistoricalTab is invoked on the
    501   // delegate.
    502   //
    503   // The boolean parameter create_historical_tab controls whether to
    504   // record these tabs and their history for reopening recently closed
    505   // tabs.
    506   void InternalCloseTab(TabContentsWrapper* contents,
    507                         int index,
    508                         bool create_historical_tabs);
    509 
    510   TabContentsWrapper* GetContentsAt(int index) const;
    511 
    512   // If the TabContentsWrapper at |to_index| differs from |old_contents|
    513   // notifies observers.
    514   void NotifyTabSelectedIfChanged(TabContentsWrapper* old_contents,
    515                                   int to_index,
    516                                   bool user_gesture);
    517 
    518   // Notifies the observers the selection changed. |old_selected_index| gives
    519   // the old selected index.
    520   void NotifySelectionChanged(int old_selected_index);
    521 
    522   // Returns the number of New Tab tabs in the TabStripModel.
    523   int GetNewTabCount() const;
    524 
    525   // Selects either the next tab (|foward| is true), or the previous tab
    526   // (|forward| is false).
    527   void SelectRelativeTab(bool forward);
    528 
    529   // Does the work of MoveTabContentsAt. This has no checks to make sure the
    530   // position is valid, those are done in MoveTabContentsAt.
    531   void MoveTabContentsAtImpl(int index,
    532                              int to_position,
    533                              bool select_after_move);
    534 
    535   // Implementation of MoveSelectedTabsTo. Moves |length| of the selected tabs
    536   // starting at |start| to |index|. See MoveSelectedTabsTo for more details.
    537   void MoveSelectedTabsToImpl(int index, size_t start, size_t length);
    538 
    539   // Returns true if the tab represented by the specified data has an opener
    540   // that matches the specified one. If |use_group| is true, then this will
    541   // fall back to check the group relationship as well.
    542   struct TabContentsData;
    543   static bool OpenerMatches(const TabContentsData* data,
    544                             const NavigationController* opener,
    545                             bool use_group);
    546 
    547   // Sets the group/opener of any tabs that reference |tab| to NULL.
    548   void ForgetOpenersAndGroupsReferencing(const NavigationController* tab);
    549 
    550   // Our delegate.
    551   TabStripModelDelegate* delegate_;
    552 
    553   // A hunk of data representing a TabContents and (optionally) the
    554   // NavigationController that spawned it. This memory only sticks around while
    555   // the TabContents is in the current TabStripModel, unless otherwise
    556   // specified in code.
    557   struct TabContentsData {
    558     explicit TabContentsData(TabContentsWrapper* a_contents)
    559         : contents(a_contents),
    560           reset_group_on_select(false),
    561           pinned(false),
    562           blocked(false) {
    563       SetGroup(NULL);
    564     }
    565 
    566     // Create a relationship between this TabContents and other TabContentses.
    567     // Used to identify which TabContents to select next after one is closed.
    568     void SetGroup(NavigationController* a_group) {
    569       group = a_group;
    570       opener = a_group;
    571     }
    572 
    573     // Forget the opener relationship so that when this TabContents is closed
    574     // unpredictable re-selection does not occur.
    575     void ForgetOpener() {
    576       opener = NULL;
    577     }
    578 
    579     TabContentsWrapper* contents;
    580     // We use NavigationControllers here since they more closely model the
    581     // "identity" of a Tab, TabContents can change depending on the URL loaded
    582     // in the Tab.
    583     // The group is used to model a set of tabs spawned from a single parent
    584     // tab. This value is preserved for a given tab as long as the tab remains
    585     // navigated to the link it was initially opened at or some navigation from
    586     // that page (i.e. if the user types or visits a bookmark or some other
    587     // navigation within that tab, the group relationship is lost). This
    588     // property can safely be used to implement features that depend on a
    589     // logical group of related tabs.
    590     NavigationController* group;
    591     // The owner models the same relationship as group, except it is more
    592     // easily discarded, e.g. when the user switches to a tab not part of the
    593     // same group. This property is used to determine what tab to select next
    594     // when one is closed.
    595     NavigationController* opener;
    596     // True if our group should be reset the moment selection moves away from
    597     // this Tab. This is the case for tabs opened in the foreground at the end
    598     // of the TabStrip while viewing another Tab. If these tabs are closed
    599     // before selection moves elsewhere, their opener is selected. But if
    600     // selection shifts to _any_ tab (including their opener), the group
    601     // relationship is reset to avoid confusing close sequencing.
    602     bool reset_group_on_select;
    603 
    604     // Is the tab pinned?
    605     bool pinned;
    606 
    607     // Is the tab interaction blocked by a modal dialog?
    608     bool blocked;
    609   };
    610 
    611   // The TabContents data currently hosted within this TabStripModel.
    612   typedef std::vector<TabContentsData*> TabContentsDataVector;
    613   TabContentsDataVector contents_data_;
    614 
    615   // A profile associated with this TabStripModel, used when creating new Tabs.
    616   Profile* profile_;
    617 
    618   // True if all tabs are currently being closed via CloseAllTabs.
    619   bool closing_all_;
    620 
    621   // An object that determines where new Tabs should be inserted and where
    622   // selection should move when a Tab is closed.
    623   TabStripModelOrderController* order_controller_;
    624 
    625   // Our observers.
    626   typedef ObserverList<TabStripModelObserver> TabStripModelObservers;
    627   TabStripModelObservers observers_;
    628 
    629   // A scoped container for notification registries.
    630   NotificationRegistrar registrar_;
    631 
    632   TabStripSelectionModel selection_model_;
    633 
    634   DISALLOW_IMPLICIT_CONSTRUCTORS(TabStripModel);
    635 };
    636 
    637 #endif  // CHROME_BROWSER_TABS_TAB_STRIP_MODEL_H_
    638