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