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