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 #include "chrome/browser/tabs/tab_strip_model_order_controller.h" 6 7 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 8 9 /////////////////////////////////////////////////////////////////////////////// 10 // TabStripModelOrderController, public: 11 12 TabStripModelOrderController::TabStripModelOrderController( 13 TabStripModel* tabstrip) 14 : tabstrip_(tabstrip), 15 insertion_policy_(TabStripModel::INSERT_AFTER) { 16 tabstrip_->AddObserver(this); 17 } 18 19 TabStripModelOrderController::~TabStripModelOrderController() { 20 tabstrip_->RemoveObserver(this); 21 } 22 23 int TabStripModelOrderController::DetermineInsertionIndex( 24 TabContentsWrapper* new_contents, 25 PageTransition::Type transition, 26 bool foreground) { 27 int tab_count = tabstrip_->count(); 28 if (!tab_count) 29 return 0; 30 31 // NOTE: TabStripModel enforces that all non-mini-tabs occur after mini-tabs, 32 // so we don't have to check here too. 33 if (transition == PageTransition::LINK && tabstrip_->active_index() != -1) { 34 int delta = (insertion_policy_ == TabStripModel::INSERT_AFTER) ? 1 : 0; 35 if (foreground) { 36 // If the page was opened in the foreground by a link click in another 37 // tab, insert it adjacent to the tab that opened that link. 38 return tabstrip_->active_index() + delta; 39 } 40 NavigationController* opener = 41 &tabstrip_->GetSelectedTabContents()->controller(); 42 // Get the index of the next item opened by this tab, and insert after 43 // it... 44 int index; 45 if (insertion_policy_ == TabStripModel::INSERT_AFTER) { 46 index = tabstrip_->GetIndexOfLastTabContentsOpenedBy( 47 opener, tabstrip_->active_index()); 48 } else { 49 index = tabstrip_->GetIndexOfFirstTabContentsOpenedBy( 50 opener, tabstrip_->active_index()); 51 } 52 if (index != TabStripModel::kNoTab) 53 return index + delta; 54 // Otherwise insert adjacent to opener... 55 return tabstrip_->active_index() + delta; 56 } 57 // In other cases, such as Ctrl+T, open at the end of the strip. 58 return DetermineInsertionIndexForAppending(); 59 } 60 61 int TabStripModelOrderController::DetermineInsertionIndexForAppending() { 62 return (insertion_policy_ == TabStripModel::INSERT_AFTER) ? 63 tabstrip_->count() : 0; 64 } 65 66 int TabStripModelOrderController::DetermineNewSelectedIndex( 67 int removing_index) const { 68 int tab_count = tabstrip_->count(); 69 DCHECK(removing_index >= 0 && removing_index < tab_count); 70 NavigationController* parent_opener = 71 tabstrip_->GetOpenerOfTabContentsAt(removing_index); 72 // First see if the index being removed has any "child" tabs. If it does, we 73 // want to select the first in that child group, not the next tab in the same 74 // group of the removed tab. 75 NavigationController* removed_controller = 76 &tabstrip_->GetTabContentsAt(removing_index)->controller(); 77 // The parent opener should never be the same as the controller being removed. 78 DCHECK(parent_opener != removed_controller); 79 int index = tabstrip_->GetIndexOfNextTabContentsOpenedBy(removed_controller, 80 removing_index, 81 false); 82 if (index != TabStripModel::kNoTab) 83 return GetValidIndex(index, removing_index); 84 85 if (parent_opener) { 86 // If the tab was in a group, shift selection to the next tab in the group. 87 int index = tabstrip_->GetIndexOfNextTabContentsOpenedBy(parent_opener, 88 removing_index, 89 false); 90 if (index != TabStripModel::kNoTab) 91 return GetValidIndex(index, removing_index); 92 93 // If we can't find a subsequent group member, just fall back to the 94 // parent_opener itself. Note that we use "group" here since opener is 95 // reset by select operations.. 96 index = tabstrip_->GetIndexOfController(parent_opener); 97 if (index != TabStripModel::kNoTab) 98 return GetValidIndex(index, removing_index); 99 } 100 101 // No opener set, fall through to the default handler... 102 int selected_index = tabstrip_->active_index(); 103 if (selected_index >= (tab_count - 1)) 104 return selected_index - 1; 105 106 return selected_index; 107 } 108 109 void TabStripModelOrderController::TabSelectedAt( 110 TabContentsWrapper* old_contents, 111 TabContentsWrapper* new_contents, 112 int index, 113 bool user_gesture) { 114 if (old_contents == new_contents) 115 return; 116 117 NavigationController* old_opener = NULL; 118 if (old_contents) { 119 int index = tabstrip_->GetIndexOfTabContents(old_contents); 120 if (index != TabStripModel::kNoTab) { 121 old_opener = tabstrip_->GetOpenerOfTabContentsAt(index); 122 123 // Forget any group/opener relationships that need to be reset whenever 124 // selection changes (see comment in TabStripModel::AddTabContentsAt). 125 if (tabstrip_->ShouldResetGroupOnSelect(old_contents)) 126 tabstrip_->ForgetGroup(old_contents); 127 } 128 } 129 NavigationController* new_opener = 130 tabstrip_->GetOpenerOfTabContentsAt(index); 131 if (user_gesture && new_opener != old_opener && 132 new_opener != &old_contents->controller() && 133 old_opener != &new_contents->controller()) { 134 tabstrip_->ForgetAllOpeners(); 135 } 136 } 137 138 /////////////////////////////////////////////////////////////////////////////// 139 // TabStripModelOrderController, private: 140 141 int TabStripModelOrderController::GetValidIndex( 142 int index, int removing_index) const { 143 if (removing_index < index) 144 index = std::max(0, index - 1); 145 return index; 146 } 147