diff options
-rw-r--r-- | chrome/browser/automation/automation_provider.cc | 11 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider.h | 1 | ||||
-rw-r--r-- | chrome/browser/browser.cc | 2 | ||||
-rw-r--r-- | chrome/browser/browser_list.cc | 10 | ||||
-rw-r--r-- | chrome/browser/browser_list.h | 4 | ||||
-rw-r--r-- | chrome/browser/sessions/tab_restore_service.cc | 22 | ||||
-rw-r--r-- | chrome/browser/sessions/tab_restore_service.h | 15 | ||||
-rw-r--r-- | chrome/browser/tab_restore_uitest.cc | 127 | ||||
-rw-r--r-- | chrome/test/automation/automation_messages_internal.h | 4 | ||||
-rw-r--r-- | chrome/test/automation/browser_proxy.cc | 2 | ||||
-rw-r--r-- | chrome/test/automation/browser_proxy.h | 2 | ||||
-rw-r--r-- | chrome/test/automation/tab_proxy.cc | 12 | ||||
-rw-r--r-- | chrome/test/automation/tab_proxy.h | 3 | ||||
-rw-r--r-- | chrome/test/ui/ui_test.cc | 10 | ||||
-rw-r--r-- | chrome/test/ui/ui_test.h | 3 |
15 files changed, 221 insertions, 7 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 1845fd7..9823840 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -930,6 +930,7 @@ void AutomationProvider::OnMessageReceived(const IPC::Message& message) { #endif // defined(OS_WIN) IPC_MESSAGE_HANDLER(AutomationMsg_TabProcessID, GetTabProcessID) IPC_MESSAGE_HANDLER(AutomationMsg_TabTitle, GetTabTitle) + IPC_MESSAGE_HANDLER(AutomationMsg_TabIndex, GetTabIndex) IPC_MESSAGE_HANDLER(AutomationMsg_TabURL, GetTabURL) IPC_MESSAGE_HANDLER(AutomationMsg_ShelfVisibility, GetShelfVisibility) @@ -1745,6 +1746,16 @@ void AutomationProvider::GetTabTitle(int handle, int* title_string_size, } } +void AutomationProvider::GetTabIndex(int handle, int* tabstrip_index) { + *tabstrip_index = -1; // -1 is the error code + + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + Browser* browser = Browser::GetBrowserForController(tab, NULL); + *tabstrip_index = browser->tabstrip_model()->GetIndexOfController(tab); + } +} + void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) { if (window_tracker_->ContainsHandle(handle)) { window_tracker_->Remove(window_tracker_->GetResource(handle)); diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h index bf08286..65f8906 100644 --- a/chrome/browser/automation/automation_provider.h +++ b/chrome/browser/automation/automation_provider.h @@ -174,6 +174,7 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>, #endif // defined(OS_WIN) void GetTabProcessID(int handle, int* process_id); void GetTabTitle(int handle, int* title_string_size, std::wstring* title); + void GetTabIndex(int handle, int* tabstrip_index); void GetTabURL(int handle, bool* success, GURL* url); void HandleUnused(const IPC::Message& message, int handle); void NavigateToURL(int handle, const GURL& url, IPC::Message* reply_message); diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index a8501d9..83cd796 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -554,6 +554,8 @@ TabContents* Browser::AddRestoredTab( new_tab->controller().RestoreFromState(navigations, selected_navigation); tabstrip_model_.InsertTabContentsAt(tab_index, new_tab, select, false); + if (select) + window_->Activate(); if (profile_->HasSessionService()) { SessionService* session_service = profile_->GetSessionService(); if (session_service) diff --git a/chrome/browser/browser_list.cc b/chrome/browser/browser_list.cc index 6665d15..411583b 100644 --- a/chrome/browser/browser_list.cc +++ b/chrome/browser/browser_list.cc @@ -211,6 +211,16 @@ Browser* BrowserList::FindBrowserWithType(Profile* p, Browser::Type t) { } // static +Browser* BrowserList::FindBrowserWithID(SessionID::id_type desired_id) { + BrowserList::const_iterator i; + for (i = BrowserList::begin(); i != BrowserList::end(); ++i) { + if ((*i)->session_id().id() == desired_id) + return *i; + } + return NULL; +} + +// static size_t BrowserList::GetBrowserCountForType(Profile* p, Browser::Type type) { BrowserList::const_iterator i; size_t result = 0; diff --git a/chrome/browser/browser_list.h b/chrome/browser/browser_list.h index 63ea28d..858e97e 100644 --- a/chrome/browser/browser_list.h +++ b/chrome/browser/browser_list.h @@ -55,6 +55,10 @@ class BrowserList { // is returned. Returns NULL if no such browser currently exists. static Browser* FindBrowserWithType(Profile* p, Browser::Type t); + // Find an existing browser with the provided ID. Returns NULL if no such + // browser currently exists. + static Browser* FindBrowserWithID(SessionID::id_type desired_id); + // Closes all browsers. If use_post is true the windows are closed by way of // posting a WM_CLOSE message, otherwise the windows are closed directly. In // almost all cases you'll want to use true, the one exception is ending diff --git a/chrome/browser/sessions/tab_restore_service.cc b/chrome/browser/sessions/tab_restore_service.cc index 5892013..d61e42a 100644 --- a/chrome/browser/sessions/tab_restore_service.cc +++ b/chrome/browser/sessions/tab_restore_service.cc @@ -130,6 +130,13 @@ void TabRestoreService::CreateHistoricalTab(NavigationController* tab) { if (local_tab->navigations.empty()) return; + // browser may be NULL when running unit tests. + if (browser) { + local_tab->browser_id = browser->session_id().id(); + local_tab->tabstrip_index = + browser->tabstrip_model()->GetIndexOfController(tab); + } + AddEntry(local_tab.release(), true, true); } @@ -221,8 +228,19 @@ void TabRestoreService::RestoreEntryById(Browser* browser, browser->ReplaceRestoredTab(tab->navigations, tab->current_navigation_index); } else { - browser->AddRestoredTab(tab->navigations, browser->tab_count(), - tab->current_navigation_index, true); + // Use the tab's former browser and index, if available. + Browser* tab_browser = NULL; + int tab_index = -1; + if (tab->has_browser()) + tab_browser = BrowserList::FindBrowserWithID(tab->browser_id); + if (tab_browser) + tab_index = tab->tabstrip_index; + else + tab_browser = browser; + if (tab_index < 0 || tab_index > browser->tab_count()) + tab_index = browser->tab_count(); + tab_browser->AddRestoredTab(tab->navigations, tab_index, + tab->current_navigation_index, true); } } else if (entry->type == WINDOW) { const Window* window = static_cast<Window*>(entry); diff --git a/chrome/browser/sessions/tab_restore_service.h b/chrome/browser/sessions/tab_restore_service.h index b768385..c728652 100644 --- a/chrome/browser/sessions/tab_restore_service.h +++ b/chrome/browser/sessions/tab_restore_service.h @@ -63,13 +63,26 @@ class TabRestoreService : public BaseSessionService { // Represents a previously open tab. struct Tab : public Entry { - Tab() : Entry(TAB), current_navigation_index(-1) {} + Tab() + : Entry(TAB), + current_navigation_index(-1), + browser_id(0), + tabstrip_index(-1) {} + + bool has_browser() const { return browser_id > 0; } // The navigations. std::vector<TabNavigation> navigations; // Index of the selected navigation in navigations. int current_navigation_index; + + // The ID of the browser to which this tab belonged, so it can be restored + // there. May be 0 (an invalid SessionID) when restoring an entire session. + SessionID::id_type browser_id; + + // Index within the tab strip. May be -1 for an unknown index. + int tabstrip_index; }; // Represents a previously open window. diff --git a/chrome/browser/tab_restore_uitest.cc b/chrome/browser/tab_restore_uitest.cc index 6a16c9b..109c768 100644 --- a/chrome/browser/tab_restore_uitest.cc +++ b/chrome/browser/tab_restore_uitest.cc @@ -12,6 +12,7 @@ #include "chrome/common/pref_names.h" #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/automation/browser_proxy.h" +#include "chrome/test/automation/window_proxy.h" #include "chrome/test/ui/ui_test.h" #include "googleurl/src/gurl.h" #include "net/base/net_util.h" @@ -49,6 +50,17 @@ class TabRestoreUITest : public UITest { action_max_timeout_ms())); } + // Ensure that the given browser occupies the currently active window. + void CheckActiveWindow(const BrowserProxy* browser) { + // The EXPECT_TRUE may fail during manual debugging, as well as if a user + // does other things while running the tests, because Chromium won't be + // the foremost application at all. + bool is_active = false; + scoped_ptr<WindowProxy> window_proxy(browser->GetWindow()); + ASSERT_TRUE(window_proxy->IsActive(&is_active)); + EXPECT_TRUE(is_active); + } + GURL url1_; GURL url2_; @@ -56,36 +68,144 @@ class TabRestoreUITest : public UITest { DISALLOW_EVIL_CONSTRUCTORS(TabRestoreUITest); }; +// Close the end tab in the current window, then restore it. The tab should be +// in its original position, and active. TEST_F(TabRestoreUITest, Basic) { scoped_ptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); int tab_count; ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + int starting_tab_count = tab_count; // Add a tab browser_proxy->AppendTab(url1_); ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(tab_count + 1, action_max_timeout_ms())); ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); - scoped_ptr<TabProxy> new_tab(browser_proxy->GetTab(tab_count - 1)); + ASSERT_EQ(starting_tab_count + 1, tab_count); + + int closed_tab_index = tab_count - 1; + scoped_ptr<TabProxy> new_tab(browser_proxy->GetTab(closed_tab_index)); // Make sure we're at url. new_tab->NavigateToURL(url1_); // Close the tab. new_tab->Close(true); new_tab.reset(); + ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + ASSERT_EQ(starting_tab_count, tab_count); RestoreTab(); - // And make sure the URL matches. + // And make sure everything looks right. + ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + ASSERT_EQ(starting_tab_count + 1, tab_count); + ASSERT_EQ(closed_tab_index, GetActiveTabIndex()); ASSERT_EQ(url1_, GetActiveTabURL()); } +// Close a tab not at the end of the current window, then restore it. The tab +// should be in its original position, and active. +TEST_F(TabRestoreUITest, MiddleTab) { + scoped_ptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); + + int tab_count; + ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + int starting_tab_count = tab_count; + + // Add a couple of tabs + browser_proxy->AppendTab(url1_); + ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(tab_count + 1, + action_max_timeout_ms())); + browser_proxy->AppendTab(url1_); + ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(tab_count + 2, + action_max_timeout_ms())); + browser_proxy->AppendTab(url1_); + ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(tab_count + 3, + action_max_timeout_ms())); + ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + ASSERT_EQ(starting_tab_count + 3, tab_count); + + // Close one in the middle + int closed_tab_index = starting_tab_count + 1; + scoped_ptr<TabProxy> new_tab(browser_proxy->GetTab(closed_tab_index)); + // Make sure we're at url. + new_tab->NavigateToURL(url1_); + // Close the tab. + new_tab->Close(true); + new_tab.reset(); + ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + ASSERT_EQ(starting_tab_count + 2, tab_count); + + RestoreTab(); + + // And make sure everything looks right. + ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + ASSERT_EQ(starting_tab_count + 3, tab_count); + ASSERT_EQ(closed_tab_index, GetActiveTabIndex()); + ASSERT_EQ(url1_, GetActiveTabURL()); +} + +// Close a tab, switch windows, then restore the tab. The tab should be in its +// original window and position, and active. TEST_F(TabRestoreUITest, RestoreToDifferentWindow) { + scoped_ptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); + + CheckActiveWindow(browser_proxy.get()); + + int tab_count; + ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + int starting_tab_count = tab_count; + + // Add a couple of tabs + browser_proxy->AppendTab(url1_); + ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(tab_count + 1, + action_max_timeout_ms())); + browser_proxy->AppendTab(url1_); + ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(tab_count + 2, + action_max_timeout_ms())); + browser_proxy->AppendTab(url1_); + ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(tab_count + 3, + action_max_timeout_ms())); + ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + ASSERT_EQ(starting_tab_count + 3, tab_count); + + // Close one in the middle + int closed_tab_index = starting_tab_count + 1; + scoped_ptr<TabProxy> new_tab(browser_proxy->GetTab(closed_tab_index)); + // Make sure we're at url. + new_tab->NavigateToURL(url1_); + // Close the tab. + new_tab->Close(true); + new_tab.reset(); + ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + ASSERT_EQ(starting_tab_count + 2, tab_count); + + // Create a new browser. + ASSERT_TRUE(automation()->OpenNewBrowserWindow(false)); + ASSERT_TRUE(automation()->WaitForWindowCountToBecome( + 2, action_max_timeout_ms())); + + CheckActiveWindow(automation()->GetBrowserWindow(1)); + + RestoreTab(); + + // And make sure everything looks right. + CheckActiveWindow(browser_proxy.get()); + ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); + EXPECT_EQ(starting_tab_count + 3, tab_count); + ASSERT_EQ(closed_tab_index, GetActiveTabIndex()); + ASSERT_EQ(url1_, GetActiveTabURL()); +} + +// Close a tab, open a new window, close the first window, then restore the +// tab. It should be at the end of the current (new) window's tabstrip. +TEST_F(TabRestoreUITest, RestoreFromClosedWindow) { // This test is disabled on win2k. See bug 1215881. if (win_util::GetWinVersion() == win_util::WINVERSION_2000) return; scoped_ptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); + CheckActiveWindow(browser_proxy.get()); int tab_count; ASSERT_TRUE(browser_proxy->GetTabCount(&tab_count)); @@ -106,6 +226,7 @@ TEST_F(TabRestoreUITest, RestoreToDifferentWindow) { ASSERT_TRUE(automation()->OpenNewBrowserWindow(false)); ASSERT_TRUE(automation()->WaitForWindowCountToBecome( 2, action_max_timeout_ms())); + CheckActiveWindow(automation()->GetBrowserWindow(1)); // Close the first browser. EXPECT_TRUE(tab_proxy->Close(true)); @@ -118,7 +239,9 @@ TEST_F(TabRestoreUITest, RestoreToDifferentWindow) { RestoreTab(); + // Tab should be at the end of the current (only) window. browser_proxy.reset(automation()->GetBrowserWindow(0)); + CheckActiveWindow(browser_proxy.get()); tab_proxy.reset(browser_proxy->GetActiveTab()); // And make sure the URLs matches. ASSERT_EQ(url2_, GetActiveTabURL()); diff --git a/chrome/test/automation/automation_messages_internal.h b/chrome/test/automation/automation_messages_internal.h index ca48ad6..16b0a42 100644 --- a/chrome/test/automation/automation_messages_internal.h +++ b/chrome/test/automation/automation_messages_internal.h @@ -889,4 +889,8 @@ IPC_BEGIN_MESSAGES(Automation) // Tab load complete IPC_MESSAGE_ROUTED1(AutomationMsg_TabLoaded, GURL) + // This message requests the tabstrip index of the tab with the given handle. + // The return value contains the index, which will be -1 on failure. + IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_TabIndex, int, int) + IPC_END_MESSAGES(Automation) diff --git a/chrome/test/automation/browser_proxy.cc b/chrome/test/automation/browser_proxy.cc index 8757a5a..d8240a0 100644 --- a/chrome/test/automation/browser_proxy.cc +++ b/chrome/test/automation/browser_proxy.cc @@ -364,7 +364,7 @@ bool BrowserProxy::SetBooleanPreference(const std::wstring& name, return result; } -WindowProxy* BrowserProxy::GetWindow() { +WindowProxy* BrowserProxy::GetWindow() const { if (!is_valid()) return false; diff --git a/chrome/test/automation/browser_proxy.h b/chrome/test/automation/browser_proxy.h index 1e3508b..68d75bae 100644 --- a/chrome/test/automation/browser_proxy.h +++ b/chrome/test/automation/browser_proxy.h @@ -103,7 +103,7 @@ class BrowserProxy : public AutomationResourceProxy { // retreive view bounds, simulate clicks and key press events. The caller // owns the returned WindowProxy. // On failure, returns NULL. - WindowProxy* GetWindow(); + WindowProxy* GetWindow() const; // Returns an AutocompleteEdit for this browser's window. It can be used to // manipulate the omnibox. The caller owns the returned pointer. diff --git a/chrome/test/automation/tab_proxy.cc b/chrome/test/automation/tab_proxy.cc index 088bd69..811f926 100644 --- a/chrome/test/automation/tab_proxy.cc +++ b/chrome/test/automation/tab_proxy.cc @@ -30,6 +30,18 @@ bool TabProxy::GetTabTitle(std::wstring* title) const { return succeeded; } +bool TabProxy::GetTabIndex(int* index) const { + if (!is_valid()) + return false; + + if (!index) { + NOTREACHED(); + return false; + } + + return sender_->Send(new AutomationMsg_TabIndex(0, handle_, index)); +} + bool TabProxy::IsShelfVisible(bool* is_visible) { if (!is_valid()) return false; diff --git a/chrome/test/automation/tab_proxy.h b/chrome/test/automation/tab_proxy.h index 4bdb4a2..86f8149 100644 --- a/chrome/test/automation/tab_proxy.h +++ b/chrome/test/automation/tab_proxy.h @@ -42,6 +42,9 @@ class TabProxy : public AutomationResourceProxy { // Gets the title of the tab. bool GetTabTitle(std::wstring* title) const; + // Gets the tabstrip index of the tab. + bool GetTabIndex(int* index) const; + // Gets the number of constrained window for this tab. bool GetConstrainedWindowCount(int* count) const; diff --git a/chrome/test/ui/ui_test.cc b/chrome/test/ui/ui_test.cc index ddea594..620637e 100644 --- a/chrome/test/ui/ui_test.cc +++ b/chrome/test/ui/ui_test.cc @@ -566,6 +566,16 @@ std::wstring UITest::GetActiveTabTitle() { return title; } +int UITest::GetActiveTabIndex() { + scoped_ptr<TabProxy> tab_proxy(GetActiveTab()); + if (!tab_proxy.get()) + return -1; + + int index; + EXPECT_TRUE(tab_proxy->GetTabIndex(&index)); + return index; +} + bool UITest::IsBrowserRunning() { return CrashAwareSleep(0); } diff --git a/chrome/test/ui/ui_test.h b/chrome/test/ui/ui_test.h index 3b37b98..e3a7c79 100644 --- a/chrome/test/ui/ui_test.h +++ b/chrome/test/ui/ui_test.h @@ -103,6 +103,9 @@ class UITest : public testing::Test { // Returns the title of the currently active tab. std::wstring GetActiveTabTitle(); + // Returns the tabstrip index of the currently active tab, or -1 on error. + int GetActiveTabIndex(); + // Returns true when the browser process is running, independent if any // renderer process exists or not. It will returns false if an user closed the // window or if the browser process died by itself. |