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