Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / tabs / tab_strip_model.h
blobbf2b46756b17d678c19633ee15bbfebb0fef9b1d
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.
5 #ifndef CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_H_
6 #define CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_H_
8 #include <vector>
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"
16 class Profile;
17 class TabStripModelDelegate;
18 class TabStripModelOrderController;
20 namespace content {
21 class WebContents;
24 ////////////////////////////////////////////////////////////////////////////////
26 // TabStripModel
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.
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.
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.
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.
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,
66 // Indicates the tab was closed by the user. If true,
67 // WebContents::SetClosedByUserGesture(true) is invoked.
68 CLOSE_USER_GESTURE = 1 << 0,
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,
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,
81 // The tab should be active.
82 ADD_ACTIVE = 1 << 0,
84 // The tab should be pinned.
85 ADD_PINNED = 1 << 1,
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,
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,
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,
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,
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,
115 // New tab was opened through the context menu on the tab strip.
116 NEW_TAB_CONTEXT_MENU,
118 // Number of enum entries, used for UMA histogram reporting macros.
119 NEW_TAB_ENUM_COUNT,
122 static const int kNoTab = -1;
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();
129 // Retrieves the TabStripModelDelegate associated with this TabStripModel.
130 TabStripModelDelegate* delegate() const { return delegate_; }
132 // Add and remove observers to changes within this TabStripModel.
133 void AddObserver(TabStripModelObserver* observer);
134 void RemoveObserver(TabStripModelObserver* observer);
136 // Retrieve the number of WebContentses/emptiness of the TabStripModel.
137 int count() const { return static_cast<int>(contents_data_.size()); }
138 bool empty() const { return contents_data_.empty(); }
140 // Retrieve the Profile associated with this TabStripModel.
141 Profile* profile() const { return profile_; }
143 // Retrieve the index of the currently active WebContents.
144 int active_index() const { return selection_model_.active(); }
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.
150 bool closing_all() const { return closing_all_; }
152 // Access the order controller. Exposed only for unit tests.
153 TabStripModelOrderController* order_controller() const {
154 return order_controller_.get();
157 // Basic API /////////////////////////////////////////////////////////////////
159 // Determines if the specified index is contained within the TabStripModel.
160 bool ContainsIndex(int index) const;
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);
166 // Adds the specified WebContents at the specified location.
167 // |add_types| is a bitmask of AddTabTypes; see it for details.
169 // All append/insert methods end up in this method.
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);
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);
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);
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);
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);
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);
213 // Adds tab at |index| to the currently selected tabs, without changing the
214 // active tab index.
215 void AddTabAtToSelection(int index);
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);
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);
245 // Returns the currently active WebContents, or NULL if there is none.
246 content::WebContents* GetActiveWebContents() const;
248 // Returns the WebContents at the specified index, or NULL if there is
249 // none.
250 content::WebContents* GetWebContentsAt(int index) const;
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;
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);
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();
267 // Returns true if there are any WebContentses that are currently loading.
268 bool TabsAreLoading() const;
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);
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);
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;
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;
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);
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();
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);
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;
317 // Changes the blocked state of the tab at |index|.
318 void SetTabBlocked(int index, bool blocked);
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);
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;
328 // Is the tab a mini-tab?
329 // See description above class for details on this.
330 bool IsMiniTab(int index) const;
332 // Is the tab at |index| an app?
333 // See description above class for details on app tabs.
334 bool IsAppTab(int index) const;
336 // Returns true if the tab at |index| is blocked by a tab modal dialog.
337 bool IsTabBlocked(int index) const;
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;
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;
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);
355 // Extends the selection from the anchor to |index|.
356 void ExtendSelectionTo(int index);
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);
362 // Makes sure the tabs from the anchor to |index| are selected. This only
363 // adds to the selection.
364 void AddSelectionFromAnchorTo(int index);
366 // Returns true if the tab at |index| is selected.
367 bool IsTabSelected(int index) const;
369 // Sets the selection to match that of |source|.
370 void SetSelectionFromModel(const ui::ListSelectionModel& source);
372 const ui::ListSelectionModel& selection_model() const {
373 return selection_model_;
376 // Command level API /////////////////////////////////////////////////////////
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);
388 // Closes the selected tabs.
389 void CloseSelectedTabs();
391 // Select adjacent tabs
392 void SelectNextTab();
393 void SelectPreviousTab();
395 // Selects the last tab in the tab strip.
396 void SelectLastTab();
398 // Swap adjacent tabs.
399 void MoveTabNext();
400 void MoveTabPrevious();
402 // View API //////////////////////////////////////////////////////////////////
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
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;
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);
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;
439 // Returns true if 'CommandTogglePinned' will pin. |index| is the index
440 // supplied to |ExecuteContextMenuCommand|.
441 bool WillContextMenuPin(int index);
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);
447 private:
448 class WebContentsData;
450 // Used when making selection notifications.
451 enum NotifyTypes {
452 NOTIFY_DEFAULT,
454 // The selection is changing from a user gesture.
455 NOTIFY_USER_GESTURE,
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;
463 // Gets the set of tab indices whose domain matches the tab at |index|.
464 void GetIndicesWithSameDomain(int index, std::vector<int>* indices);
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);
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;
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;
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.
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);
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.
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);
505 // Gets the WebContents at an index. Does no bounds checking.
506 content::WebContents* GetWebContentsAtImpl(int index) const;
508 // Notifies the observers if the active tab is being deactivated.
509 void NotifyIfTabDeactivated(content::WebContents* contents);
511 // Notifies the observers if the active tab has changed.
512 void NotifyIfActiveTabChanged(content::WebContents* old_contents,
513 NotifyTypes notify_types);
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);
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);
530 // Selects either the next tab (|forward| is true), or the previous tab
531 // (|forward| is false).
532 void SelectRelativeTab(bool forward);
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);
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);
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);
551 // Sets the group/opener of any tabs that reference the tab at |index| to that
552 // tab's group/opener respectively.
553 void FixOpenersAndGroupsReferencing(int index);
555 // Our delegate.
556 TabStripModelDelegate* delegate_;
558 // The WebContents data currently hosted within this TabStripModel.
559 typedef std::vector<WebContentsData*> WebContentsDataVector;
560 WebContentsDataVector contents_data_;
562 // A profile associated with this TabStripModel.
563 Profile* profile_;
565 // True if all tabs are currently being closed via CloseAllTabs.
566 bool closing_all_;
568 // An object that determines where new Tabs should be inserted and where
569 // selection should move when a Tab is closed.
570 scoped_ptr<TabStripModelOrderController> order_controller_;
572 // Our observers.
573 typedef ObserverList<TabStripModelObserver> TabStripModelObservers;
574 TabStripModelObservers observers_;
576 ui::ListSelectionModel selection_model_;
578 // TODO(sky): remove this; used for debugging 291265.
579 bool in_notify_;
581 base::WeakPtrFactory<TabStripModel> weak_factory_;
583 DISALLOW_IMPLICIT_CONSTRUCTORS(TabStripModel);
586 #endif // CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_H_