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