diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-03 15:52:29 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-03 15:52:29 +0000 |
commit | b334487af4e2c5b9d27e0807347f7fa94b6d89a5 (patch) | |
tree | 39d3ab8fc095c814d80c65f1df93c7e01d09eb4e /chrome | |
parent | 2823b2b8a5b66279c2eac18f62b7756e89d72828 (diff) | |
download | chromium_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.cc | 20 | ||||
-rw-r--r-- | chrome/browser/browser.h | 14 | ||||
-rw-r--r-- | chrome/browser/browser_init.cc | 4 | ||||
-rw-r--r-- | chrome/browser/sessions/session_restore.cc | 10 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model.cc | 28 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model.h | 25 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model_order_controller.cc | 37 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model_order_controller.h | 27 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model_unittest.cc | 48 |
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 |