summaryrefslogtreecommitdiffstats
path: root/chrome/browser/tabs/tab_strip_model_order_controller.cc
blob: de0ab239835cfafccffb4ba6f70bb6f0ff478e72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/tabs/tab_strip_model_order_controller.h"

#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/pref_names.h"

///////////////////////////////////////////////////////////////////////////////
// TabStripModelOrderController, public:

TabStripModelOrderController::TabStripModelOrderController(
    TabStripModel* tabstrip) : tabstrip_(tabstrip) {
  tabstrip_->AddObserver(this);
}

TabStripModelOrderController::~TabStripModelOrderController() {
  tabstrip_->RemoveObserver(this);
}

int TabStripModelOrderController::DetermineInsertionIndex(
    TabContents* new_contents,
    PageTransition::Type transition,
    bool foreground) {
  int tab_count = tabstrip_->count();
  int first_non_pinned_tab = tabstrip_->IndexOfFirstNonPinnedTab();
  if (!tab_count)
    return 0;

  if (transition == PageTransition::LINK && tabstrip_->selected_index() != -1) {
    if (foreground) {
      // If the page was opened in the foreground by a link click in another
      // tab, insert it adjacent to the tab that opened that link.
      // TODO(beng): (http://b/1085481) may want to open right of all locked
      //             tabs?
      return std::max(first_non_pinned_tab,
                      tabstrip_->selected_index() + 1);
    }
    NavigationController* opener =
        &tabstrip_->GetSelectedTabContents()->controller();
    // Get the index of the next item opened by this tab, and insert after
    // it...
    int index = tabstrip_->GetIndexOfLastTabContentsOpenedBy(
        opener, tabstrip_->selected_index());
    if (index != TabStripModel::kNoTab)
      return index + 1;
    // Otherwise insert adjacent to opener...
    return std::max(first_non_pinned_tab, tabstrip_->selected_index() + 1);
  }
  // In other cases, such as Ctrl+T, open at the end of the strip.
  return tab_count;
}

int TabStripModelOrderController::DetermineNewSelectedIndex(
    int removing_index,
    bool is_remove) const {
  int tab_count = tabstrip_->count();
  DCHECK(removing_index >= 0 && removing_index < tab_count);
  NavigationController* parent_opener =
      tabstrip_->GetOpenerOfTabContentsAt(removing_index);
  // First see if the index being removed has any "child" tabs. If it does, we
  // want to select the first in that child group, not the next tab in the same
  // group of the removed tab.
  NavigationController* removed_controller =
      &tabstrip_->GetTabContentsAt(removing_index)->controller();
  int index = tabstrip_->GetIndexOfNextTabContentsOpenedBy(removed_controller,
                                                           removing_index,
                                                           false);
  if (index != TabStripModel::kNoTab)
    return GetValidIndex(index, removing_index, is_remove);

  if (parent_opener) {
    // If the tab was in a group, shift selection to the next tab in the group.
    int index = tabstrip_->GetIndexOfNextTabContentsOpenedBy(parent_opener,
                                                             removing_index,
                                                             false);
    if (index != TabStripModel::kNoTab)
      return GetValidIndex(index, removing_index, is_remove);

    // If we can't find a subsequent group member, just fall back to the
    // parent_opener itself. Note that we use "group" here since opener is
    // reset by select operations..
    index = tabstrip_->GetIndexOfController(parent_opener);
    if (index != TabStripModel::kNoTab)
      return GetValidIndex(index, removing_index, is_remove);
  }

  // No opener set, fall through to the default handler...
  int selected_index = tabstrip_->selected_index();
  if (is_remove && selected_index >= (tab_count - 1))
    return selected_index - 1;
  return selected_index;
}

void TabStripModelOrderController::TabSelectedAt(TabContents* old_contents,
                                                 TabContents* new_contents,
                                                 int index,
                                                 bool user_gesture) {
  NavigationController* old_opener = NULL;
  if (old_contents) {
    int index = tabstrip_->GetIndexOfTabContents(old_contents);
    if (index != TabStripModel::kNoTab) {
      old_opener = tabstrip_->GetOpenerOfTabContentsAt(index);

      // Forget any group/opener relationships that need to be reset whenever
      // selection changes (see comment in TabStripModel::AddTabContentsAt).
      if (tabstrip_->ShouldResetGroupOnSelect(old_contents))
        tabstrip_->ForgetGroup(old_contents);
    }
  }
  NavigationController* new_opener =
      tabstrip_->GetOpenerOfTabContentsAt(index);
  if (user_gesture && new_opener != old_opener &&
      new_opener != &old_contents->controller() &&
      old_opener != &new_contents->controller()) {
    tabstrip_->ForgetAllOpeners();
  }
}

///////////////////////////////////////////////////////////////////////////////
// TabStripModelOrderController, private:

int TabStripModelOrderController::GetValidIndex(int index,
                                                int removing_index,
                                                bool is_remove) const {
  if (is_remove && removing_index < index)
    index = std::max(0, index - 1);
  return index;
}