tab_strip_model.h revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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
18class Profile;
19class TabStripModelDelegate;
20class TabStripModelOrderController;
21
22namespace content {
23class 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////////////////////////////////////////////////////////////////////////////////
62class 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  // TODO(sky): remove this; used for debugging 291265.
646  bool in_notify_;
647
648  DISALLOW_IMPLICIT_CONSTRUCTORS(TabStripModel);
649};
650
651#endif  // CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_H_
652