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