summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-03 15:52:29 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-03 15:52:29 +0000
commitb334487af4e2c5b9d27e0807347f7fa94b6d89a5 (patch)
tree39d3ab8fc095c814d80c65f1df93c7e01d09eb4e /chrome
parent2823b2b8a5b66279c2eac18f62b7756e89d72828 (diff)
downloadchromium_src-b334487af4e2c5b9d27e0807347f7fa94b6d89a5.zip
chromium_src-b334487af4e2c5b9d27e0807347f7fa94b6d89a5.tar.gz
chromium_src-b334487af4e2c5b9d27e0807347f7fa94b6d89a5.tar.bz2
Adds ability for newly inserted tabs to appear before other tabs. I'll
wire this up to vertical tabs shortly. BUG=none TEST=none Review URL: http://codereview.chromium.org/1687020 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46224 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/browser.cc20
-rw-r--r--chrome/browser/browser.h14
-rw-r--r--chrome/browser/browser_init.cc4
-rw-r--r--chrome/browser/sessions/session_restore.cc10
-rw-r--r--chrome/browser/tabs/tab_strip_model.cc28
-rw-r--r--chrome/browser/tabs/tab_strip_model.h25
-rw-r--r--chrome/browser/tabs/tab_strip_model_order_controller.cc37
-rw-r--r--chrome/browser/tabs/tab_strip_model_order_controller.h27
-rw-r--r--chrome/browser/tabs/tab_strip_model_unittest.cc48
9 files changed, 179 insertions, 34 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index 43e1e61..cad0d63 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -208,6 +208,7 @@ Browser::Browser(Type type, Profile* profile)
// might show vertical tabs but not show an option to turn them off.
use_vertical_tabs_.SetValue(false);
}
+ UpdateTabStripModelInsertionPolicy();
}
Browser::~Browser() {
@@ -750,6 +751,11 @@ void Browser::InProgressDownloadResponse(bool cancel_downloads) {
////////////////////////////////////////////////////////////////////////////////
// Browser, Tab adding/showing functions:
+int Browser::GetIndexForInsertionDuringRestore(int relative_index) {
+ return (tabstrip_model_.insertion_policy() == TabStripModel::INSERT_AFTER) ?
+ tab_count() : relative_index;
+}
+
TabContents* Browser::AddTabWithURL(const GURL& url,
const GURL& referrer,
PageTransition::Type transition,
@@ -982,6 +988,16 @@ NavigationController& Browser::GetOrCloneNavigationControllerForDisposition(
}
}
+void Browser::UpdateTabStripModelInsertionPolicy() {
+ tabstrip_model_.SetInsertionPolicy(UseVerticalTabs() ?
+ TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER);
+}
+
+void Browser::UseVerticalTabsChanged() {
+ UpdateTabStripModelInsertionPolicy();
+ window()->ToggleTabStripMode();
+}
+
void Browser::GoBack(WindowOpenDisposition disposition) {
UserMetrics::RecordAction(UserMetricsAction("Back"), profile_);
@@ -2141,7 +2157,7 @@ bool Browser::UseVerticalTabs() const {
void Browser::ToggleUseVerticalTabs() {
use_vertical_tabs_.SetValue(!UseVerticalTabs());
- window()->ToggleTabStripMode();
+ UseVerticalTabsChanged();
}
///////////////////////////////////////////////////////////////////////////////
@@ -2802,7 +2818,7 @@ void Browser::Observe(NotificationType type,
case NotificationType::PREF_CHANGED: {
if (*(Details<std::wstring>(details).ptr()) == prefs::kUseVerticalTabs)
- window()->ToggleTabStripMode();
+ UseVerticalTabsChanged();
else
NOTREACHED();
break;
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index 65eb214..92cf741 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -320,6 +320,12 @@ class Browser : public TabStripModelDelegate,
// Tab adding/showing functions /////////////////////////////////////////////
+ // Returns the index to insert a tab at during session restore and startup.
+ // |relative_index| gives the index of the url into the number of tabs that
+ // are going to be opened. For example, if three urls are passed in on the
+ // command line this is invoked three times with the values 0, 1 and 2.
+ int GetIndexForInsertionDuringRestore(int relative_index);
+
// Adds a new tab at the specified index. |add_types| is a bitmask of the
// values defined by AddTabTypes; see AddTabTypes for details. If |instance|
// is not null, its process will be used to render the tab. If
@@ -865,6 +871,14 @@ class Browser : public TabStripModelDelegate,
NavigationController& GetOrCloneNavigationControllerForDisposition(
WindowOpenDisposition disp);
+ // Sets the insertion policy of the tabstrip based on whether vertical tabs
+ // are enabled.
+ void UpdateTabStripModelInsertionPolicy();
+
+ // Invoked when the use vertical tabs preference changes. Resets the insertion
+ // policy of the tab strip model and notifies the window.
+ void UseVerticalTabsChanged();
+
// Data members /////////////////////////////////////////////////////////////
NotificationRegistrar registrar_;
diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc
index df87771..8a326ac 100644
--- a/chrome/browser/browser_init.cc
+++ b/chrome/browser/browser_init.cc
@@ -726,11 +726,13 @@ Browser* BrowserInit::LaunchWithProfile::OpenTabsInBrowser(
continue;
int add_types = first_tab ? Browser::ADD_SELECTED : Browser::ADD_NONE;
+ add_types |= Browser::ADD_FORCE_INDEX;
if (tabs[i].is_pinned)
add_types |= Browser::ADD_PINNED;
+ int index = browser->GetIndexForInsertionDuringRestore(i);
TabContents* tab = browser->AddTabWithURL(
- tabs[i].url, GURL(), PageTransition::START_PAGE, -1, add_types, NULL,
+ tabs[i].url, GURL(), PageTransition::START_PAGE, index, add_types, NULL,
tabs[i].app_id);
if (profile_ && first_tab && process_startup) {
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index bcc9f98..e6eb2b9 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -431,10 +431,12 @@ class SessionRestoreImpl : public NotificationObserver {
void AppendURLsToBrowser(Browser* browser,
const std::vector<GURL>& urls) {
for (size_t i = 0; i < urls.size(); ++i) {
- browser->AddTabWithURL(
- urls[i], GURL(), PageTransition::START_PAGE, -1,
- (i == 0) ? Browser::ADD_SELECTED : Browser::ADD_NONE, NULL,
- std::string());
+ int add_types = Browser::ADD_FORCE_INDEX;
+ if (i == 0)
+ add_types |= Browser::ADD_SELECTED;
+ int index = browser->GetIndexForInsertionDuringRestore(i);
+ browser->AddTabWithURL(urls[i], GURL(), PageTransition::START_PAGE, index,
+ add_types, NULL, std::string());
}
}
diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc
index 6d05ebf..f08e9c5 100644
--- a/chrome/browser/tabs/tab_strip_model.cc
+++ b/chrome/browser/tabs/tab_strip_model.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -85,6 +85,14 @@ bool TabStripModel::HasNonPhantomTabs() const {
return false;
}
+void TabStripModel::SetInsertionPolicy(InsertionPolicy policy) {
+ order_controller_->set_insertion_policy(policy);
+}
+
+TabStripModel::InsertionPolicy TabStripModel::insertion_policy() const {
+ return order_controller_->insertion_policy();
+}
+
bool TabStripModel::HasObserver(TabStripModelObserver* observer) {
return observers_.HasObserver(observer);
}
@@ -96,7 +104,8 @@ bool TabStripModel::ContainsIndex(int index) const {
void TabStripModel::AppendTabContents(TabContents* contents, bool foreground) {
// Tabs opened in the foreground using this method inherit the group of the
// previously selected tab.
- InsertTabContentsAt(count(), contents, foreground, foreground);
+ int index = order_controller_->DetermineInsertionIndexForAppending();
+ InsertTabContentsAt(index, contents, foreground, foreground);
}
void TabStripModel::InsertTabContentsAt(int index,
@@ -299,6 +308,19 @@ int TabStripModel::GetIndexOfNextTabContentsOpenedBy(
return kNoTab;
}
+int TabStripModel::GetIndexOfFirstTabContentsOpenedBy(
+ const NavigationController* opener,
+ int start_index) const {
+ DCHECK(opener);
+ DCHECK(ContainsIndex(start_index));
+
+ for (int i = 0; i < start_index; ++i) {
+ if (contents_data_[i]->opener == opener && !IsPhantomTab(i))
+ return i;
+ }
+ return kNoTab;
+}
+
int TabStripModel::GetIndexOfLastTabContentsOpenedBy(
const NavigationController* opener, int start_index) const {
DCHECK(opener);
@@ -467,7 +489,7 @@ void TabStripModel::AddTabContents(TabContents* contents,
// For all other types, respect what was passed to us, normalizing -1s and
// values that are too large.
if (index < 0 || index > count())
- index = count();
+ index = order_controller_->DetermineInsertionIndexForAppending();
}
if (transition == PageTransition::TYPED && index == count()) {
diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h
index 90b4419..2b8f183 100644
--- a/chrome/browser/tabs/tab_strip_model.h
+++ b/chrome/browser/tabs/tab_strip_model.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -278,6 +278,17 @@ class TabStripModelDelegate {
////////////////////////////////////////////////////////////////////////////////
class TabStripModel : public NotificationObserver {
public:
+ // Policy for how new tabs are inserted.
+ enum InsertionPolicy {
+ // Newly created tabs are created after the selection. This is the default.
+ INSERT_AFTER,
+
+ // Newly created tabs are inserted before the selection.
+ INSERT_BEFORE,
+ };
+
+ static const int kNoTab = -1;
+
// Construct a TabStripModel with a delegate to help it do certain things
// (See TabStripModelDelegate documentation). |delegate| cannot be NULL.
TabStripModel(TabStripModelDelegate* delegate, Profile* profile);
@@ -316,14 +327,16 @@ class TabStripModel : public NotificationObserver {
return order_controller_;
}
+ // Sets the insertion policy. Default is INSERT_AFTER.
+ void SetInsertionPolicy(InsertionPolicy policy);
+ InsertionPolicy insertion_policy() const;
+
// Returns true if |observer| is in the list of observers. This is intended
// for debugging.
bool HasObserver(TabStripModelObserver* observer);
// Basic API /////////////////////////////////////////////////////////////////
- static const int kNoTab = -1;
-
// Determines if the specified index is contained within the TabStripModel.
bool ContainsIndex(int index) const;
@@ -436,6 +449,12 @@ class TabStripModel : public NotificationObserver {
int start_index,
bool use_group) const;
+ // Returns the index of the first TabContents in the model opened by the
+ // specified opener.
+ // NOTE: this skips phantom tabs.
+ int GetIndexOfFirstTabContentsOpenedBy(const NavigationController* opener,
+ int start_index) const;
+
// Returns the index of the last TabContents in the model opened by the
// specified opener, starting at |start_index|.
// NOTE: this skips phantom tabs.
diff --git a/chrome/browser/tabs/tab_strip_model_order_controller.cc b/chrome/browser/tabs/tab_strip_model_order_controller.cc
index ad957dc..a967bd9 100644
--- a/chrome/browser/tabs/tab_strip_model_order_controller.cc
+++ b/chrome/browser/tabs/tab_strip_model_order_controller.cc
@@ -1,17 +1,18 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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/tab_contents/tab_contents.h"
-#include "chrome/common/pref_names.h"
///////////////////////////////////////////////////////////////////////////////
// TabStripModelOrderController, public:
TabStripModelOrderController::TabStripModelOrderController(
- TabStripModel* tabstrip) : tabstrip_(tabstrip) {
+ TabStripModel* tabstrip)
+ : tabstrip_(tabstrip),
+ insertion_policy_(TabStripModel::INSERT_AFTER) {
tabstrip_->AddObserver(this);
}
@@ -27,29 +28,39 @@ int TabStripModelOrderController::DetermineInsertionIndex(
if (!tab_count)
return 0;
- int first_non_app_tab = tabstrip_->IndexOfFirstNonMiniTab();
+ // 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.
- // TODO(beng): (http://b/1085481) may want to open right of all locked
- // tabs?
- return std::max(first_non_app_tab,
- tabstrip_->selected_index() + 1);
+ 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 = tabstrip_->GetIndexOfLastTabContentsOpenedBy(
- opener, tabstrip_->selected_index());
+ 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 + 1;
+ return index + delta;
// Otherwise insert adjacent to opener...
- return std::max(first_non_app_tab, tabstrip_->selected_index() + 1);
+ return tabstrip_->selected_index() + delta;
}
// In other cases, such as Ctrl+T, open at the end of the strip.
- return tab_count;
+ return DetermineInsertionIndexForAppending();
+}
+
+int TabStripModelOrderController::DetermineInsertionIndexForAppending() {
+ return (insertion_policy_ == TabStripModel::INSERT_AFTER) ?
+ tabstrip_->count() : 0;
}
int TabStripModelOrderController::DetermineNewSelectedIndex(
diff --git a/chrome/browser/tabs/tab_strip_model_order_controller.h b/chrome/browser/tabs/tab_strip_model_order_controller.h
index a74bf52..f0ff265 100644
--- a/chrome/browser/tabs/tab_strip_model_order_controller.h
+++ b/chrome/browser/tabs/tab_strip_model_order_controller.h
@@ -1,16 +1,14 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
-#ifndef CHROME_BROWSER_TABS_TAB_STRIP_MODEL_ORDER_CONTROLLER_H__
-#define CHROME_BROWSER_TABS_TAB_STRIP_MODEL_ORDER_CONTROLLER_H__
+#ifndef CHROME_BROWSER_TABS_TAB_STRIP_MODEL_ORDER_CONTROLLER_H_
+#define CHROME_BROWSER_TABS_TAB_STRIP_MODEL_ORDER_CONTROLLER_H_
-#include "chrome/browser/pref_member.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/page_transition_types.h"
class TabContents;
-class TabStripModel;
///////////////////////////////////////////////////////////////////////////////
// TabStripModelOrderController
@@ -23,12 +21,23 @@ class TabStripModelOrderController : public TabStripModelObserver {
explicit TabStripModelOrderController(TabStripModel* tabstrip);
virtual ~TabStripModelOrderController();
+ // Sets the insertion policy. Default is INSERT_AFTER.
+ void set_insertion_policy(TabStripModel::InsertionPolicy policy) {
+ insertion_policy_ = policy;
+ }
+ TabStripModel::InsertionPolicy insertion_policy() const {
+ return insertion_policy_;
+ }
+
// Determine where to place a newly opened tab by using the supplied
// transition and foreground flag to figure out how it was opened.
int DetermineInsertionIndex(TabContents* new_contents,
PageTransition::Type transition,
bool foreground);
+ // Returns the index to append tabs at.
+ int DetermineInsertionIndexForAppending();
+
// Determine where to shift selection after a tab is closed is made phantom.
// If |is_remove| is false, the tab is not being removed but rather made
// phantom (see description of phantom tabs in TabStripModel).
@@ -41,7 +50,7 @@ class TabStripModelOrderController : public TabStripModelObserver {
int index,
bool user_gesture);
- protected:
+ private:
// Returns a valid index to be selected after the tab at |removing_index| is
// closed. If |index| is after |removing_index| and |is_remove| is true,
// |index| is adjusted to reflect the fact that |removing_index| is going
@@ -49,6 +58,10 @@ class TabStripModelOrderController : public TabStripModelObserver {
int GetValidIndex(int index, int removing_index, bool is_remove) const;
TabStripModel* tabstrip_;
+
+ TabStripModel::InsertionPolicy insertion_policy_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabStripModelOrderController);
};
-#endif // CHROME_BROWSER_TABS_TAB_STRIP_MODEL_ORDER_CONTROLLER_H__
+#endif // CHROME_BROWSER_TABS_TAB_STRIP_MODEL_ORDER_CONTROLLER_H_
diff --git a/chrome/browser/tabs/tab_strip_model_unittest.cc b/chrome/browser/tabs/tab_strip_model_unittest.cc
index 44c56e6..7ffaac4 100644
--- a/chrome/browser/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/tabs/tab_strip_model_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -608,6 +608,52 @@ TEST_F(TabStripModelTest, TestLTRInsertionOptions) {
EXPECT_TRUE(tabstrip.empty());
}
+// Tests inserting tabs with InsertAfter set to false.
+TEST_F(TabStripModelTest, InsertBefore) {
+ TabStripDummyDelegate delegate(NULL);
+ TabStripModel tabstrip(&delegate, profile());
+ tabstrip.SetInsertionPolicy(TabStripModel::INSERT_BEFORE);
+ EXPECT_TRUE(tabstrip.empty());
+
+ TabContents* contents1 = CreateTabContents();
+ TabContents* contents2 = CreateTabContents();
+ TabContents* contents3 = CreateTabContents();
+
+ InsertTabContentses(&tabstrip, contents1, contents2, contents3);
+
+ // The order should be reversed.
+ EXPECT_EQ(contents3, tabstrip.GetTabContentsAt(0));
+ EXPECT_EQ(contents2, tabstrip.GetTabContentsAt(1));
+ EXPECT_EQ(contents1, tabstrip.GetTabContentsAt(2));
+
+ tabstrip.CloseAllTabs();
+ EXPECT_TRUE(tabstrip.empty());
+}
+
+// Tests opening background tabs with InsertAfter set to false.
+TEST_F(TabStripModelTest, InsertBeforeOpeners) {
+ TabStripDummyDelegate delegate(NULL);
+ TabStripModel tabstrip(&delegate, profile());
+ tabstrip.SetInsertionPolicy(TabStripModel::INSERT_BEFORE);
+ EXPECT_TRUE(tabstrip.empty());
+ TabContents* opener_contents = CreateTabContents();
+ tabstrip.AppendTabContents(opener_contents, true);
+
+ TabContents* contents1 = CreateTabContents();
+ TabContents* contents2 = CreateTabContents();
+ TabContents* contents3 = CreateTabContents();
+
+ InsertTabContentses(&tabstrip, contents1, contents2, contents3);
+
+ // The order should be reversed.
+ EXPECT_EQ(contents3, tabstrip.GetTabContentsAt(0));
+ EXPECT_EQ(contents2, tabstrip.GetTabContentsAt(1));
+ EXPECT_EQ(contents1, tabstrip.GetTabContentsAt(2));
+
+ tabstrip.CloseAllTabs();
+ EXPECT_TRUE(tabstrip.empty());
+}
+
// This test constructs a tabstrip, and then simulates loading several tabs in
// the background from link clicks on the first tab. Then it simulates opening
// a new tab from the first tab in the foreground via a link click, verifies