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
TabStripModelOrderController(TabStripModel * tabstrip)12 TabStripModelOrderController::TabStripModelOrderController(
13 TabStripModel* tabstrip)
14 : tabstrip_(tabstrip),
15 insertion_policy_(TabStripModel::INSERT_AFTER) {
16 tabstrip_->AddObserver(this);
17 }
18
~TabStripModelOrderController()19 TabStripModelOrderController::~TabStripModelOrderController() {
20 tabstrip_->RemoveObserver(this);
21 }
22
DetermineInsertionIndex(TabContentsWrapper * new_contents,PageTransition::Type transition,bool foreground)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
DetermineInsertionIndexForAppending()61 int TabStripModelOrderController::DetermineInsertionIndexForAppending() {
62 return (insertion_policy_ == TabStripModel::INSERT_AFTER) ?
63 tabstrip_->count() : 0;
64 }
65
DetermineNewSelectedIndex(int removing_index) const66 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
TabSelectedAt(TabContentsWrapper * old_contents,TabContentsWrapper * new_contents,int index,bool user_gesture)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
GetValidIndex(int index,int removing_index) const141 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