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 18 class NavigationController; 19 class Profile; 20 class TabContents; 21 class TabContentsWrapper; 22 class TabStripModelDelegate; 23 class 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 //////////////////////////////////////////////////////////////////////////////// 61 class 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. delegate()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. count()128 int count() const { return static_cast<int>(contents_data_.size()); } empty()129 bool empty() const { return contents_data_.empty(); } 130 131 // Retrieve the Profile associated with this TabStripModel. profile()132 Profile* profile() const { return profile_; } 133 134 // Retrieve the index of the currently active TabContents. active_index()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. closing_all()141 bool closing_all() const { return closing_all_; } 142 143 // Access the order controller. Exposed only for unit tests. order_controller()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 selection_model()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 { TabContentsDataTabContentsData558 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. SetGroupTabContentsData568 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. ForgetOpenerTabContentsData575 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