• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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