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.
5 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
7 #include "content/public/browser/web_contents.h"
9 ///////////////////////////////////////////////////////////////////////////////
10 // TabStripModelOrderController, public:
12 TabStripModelOrderController::TabStripModelOrderController(
13 TabStripModel
* tabstrip
)
14 : tabstrip_(tabstrip
) {
15 tabstrip_
->AddObserver(this);
18 TabStripModelOrderController::~TabStripModelOrderController() {
19 tabstrip_
->RemoveObserver(this);
22 int TabStripModelOrderController::DetermineInsertionIndex(
23 content::PageTransition transition
,
25 int tab_count
= tabstrip_
->count();
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
== content::PAGE_TRANSITION_LINK
&&
32 tabstrip_
->active_index() != -1) {
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;
38 content::WebContents
* opener
= tabstrip_
->GetActiveWebContents();
39 // Get the index of the next item opened by this tab, and insert after
41 int index
= tabstrip_
->GetIndexOfLastWebContentsOpenedBy(
42 opener
, tabstrip_
->active_index());
43 if (index
!= TabStripModel::kNoTab
)
45 // Otherwise insert adjacent to opener...
46 return tabstrip_
->active_index() + 1;
48 // In other cases, such as Ctrl+T, open at the end of the strip.
49 return tabstrip_
->count();
52 int 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
,
68 if (index
!= TabStripModel::kNoTab
)
69 return GetValidIndex(index
, removing_index
);
72 // If the tab was in a group, shift selection to the next tab in the group.
73 int index
= tabstrip_
->GetIndexOfNextWebContentsOpenedBy(parent_opener
,
76 if (index
!= TabStripModel::kNoTab
)
77 return GetValidIndex(index
, removing_index
);
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
);
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;
92 return selected_index
;
95 void TabStripModelOrderController::ActiveTabChanged(
96 content::WebContents
* old_contents
,
97 content::WebContents
* new_contents
,
100 content::WebContents
* old_opener
= NULL
;
102 int index
= tabstrip_
->GetIndexOfWebContents(old_contents
);
103 if (index
!= TabStripModel::kNoTab
) {
104 old_opener
= tabstrip_
->GetOpenerOfWebContentsAt(index
);
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
);
112 content::WebContents
* new_opener
= tabstrip_
->GetOpenerOfWebContentsAt(index
);
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();
123 ///////////////////////////////////////////////////////////////////////////////
124 // TabStripModelOrderController, private:
126 int TabStripModelOrderController::GetValidIndex(
127 int index
, int removing_index
) const {
128 if (removing_index
< index
)
129 index
= std::max(0, index
- 1);