summaryrefslogtreecommitdiffstats
path: root/chrome/browser/tabs/tab_strip_model_order_controller.cc
blob: 52730ef3886b8f48e56c2d938b3e1a6fc292e7c5 (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (c) 2010 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/ui/tab_contents/tab_contents_wrapper.h"

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

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

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

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

  // NOTE: TabStripModel enforces that all non-mini-tabs occur after mini-tabs,
  // so we don't have to check here too.
  if (transition == PageTransition::LINK && tabstrip_->selected_index() != -1) {
    int delta = (insertion_policy_ == TabStripModel::INSERT_AFTER) ? 1 : 0;
    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.
      return tabstrip_->selected_index() + delta;
    }
    NavigationController* opener =
        &tabstrip_->GetSelectedTabContents()->controller();
    // Get the index of the next item opened by this tab, and insert after
    // it...
    int index;
    if (insertion_policy_ == TabStripModel::INSERT_AFTER) {
      index = tabstrip_->GetIndexOfLastTabContentsOpenedBy(
          opener, tabstrip_->selected_index());
    } else {
      index = tabstrip_->GetIndexOfFirstTabContentsOpenedBy(
          opener, tabstrip_->selected_index());
    }
    if (index != TabStripModel::kNoTab)
      return index + delta;
    // Otherwise insert adjacent to opener...
    return tabstrip_->selected_index() + delta;
  }
  // In other cases, such as Ctrl+T, open at the end of the strip.
  return DetermineInsertionIndexForAppending();
}

int TabStripModelOrderController::DetermineInsertionIndexForAppending() {
  return (insertion_policy_ == TabStripModel::INSERT_AFTER) ?
      tabstrip_->count() : 0;
}

int TabStripModelOrderController::DetermineNewSelectedIndex(
    int removing_index, volatile int* reason) 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();
  // The parent opener should never be the same as the controller being removed.
  CHECK(parent_opener != removed_controller);
  int index = tabstrip_->GetIndexOfNextTabContentsOpenedBy(removed_controller,
                                                           removing_index,
                                                           false);
  if (index != TabStripModel::kNoTab) {
    *reason = 1;
    return GetValidIndex(index, removing_index);
  }

  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) {
      *reason = 2;
      return GetValidIndex(index, removing_index);
    }

    // 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) {
      *reason = 3;
      return GetValidIndex(index, removing_index);
    }
  }

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

  *reason = 5;
  return selected_index;
}

void TabStripModelOrderController::TabSelectedAt(
    TabContentsWrapper* old_contents,
    TabContentsWrapper* 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) const {
  if (removing_index < index)
    index = std::max(0, index - 1);
  return index;
}