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