summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-18 17:12:27 +0000
committerrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-18 17:12:27 +0000
commitf74d445459f6bf0479acc08c9c851c12540e6986 (patch)
tree8096e61b722ccf0aa0cbdb724353c8d154963802 /chrome
parent06a7a1a48f1d70b0b47f7014d73680e2a520a13f (diff)
downloadchromium_src-f74d445459f6bf0479acc08c9c851c12540e6986.zip
chromium_src-f74d445459f6bf0479acc08c9c851c12540e6986.tar.gz
chromium_src-f74d445459f6bf0479acc08c9c851c12540e6986.tar.bz2
Allow the TabRestoreService to restore individual tabs from a window.
BUG=43787 TEST=Create a window and navigate three tabs. Close the window. Go to History-->3 Tabs and select 1 tab. It is restored, but the others are not. Review URL: http://codereview.chromium.org/2799005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50252 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/sessions/session_restore_browsertest.cc56
-rw-r--r--chrome/browser/sessions/tab_restore_service.cc193
-rw-r--r--chrome/browser/sessions/tab_restore_service.h13
3 files changed, 207 insertions, 55 deletions
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index 69dba05..41edc2a 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -6,7 +6,9 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/defaults.h"
+#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/page_transition_types.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
@@ -59,3 +61,57 @@ IN_PROC_BROWSER_TEST_F(SessionRestoreTest,
// And the first url should be url.
EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL());
}
+
+
+IN_PROC_BROWSER_TEST_F(SessionRestoreTest, RestoreIndividualTabFromWindow) {
+ GURL url1(ui_test_utils::GetTestUrl(
+ FilePath(FilePath::kCurrentDirectory),
+ FilePath(FILE_PATH_LITERAL("title1.html"))));
+ GURL url2(ui_test_utils::GetTestUrl(
+ FilePath(FilePath::kCurrentDirectory),
+ FilePath(FILE_PATH_LITERAL("title2.html"))));
+ GURL url3(ui_test_utils::GetTestUrl(
+ FilePath(FilePath::kCurrentDirectory),
+ FilePath(FILE_PATH_LITERAL("title3.html"))));
+
+ // Add and navigate three tabs.
+ ui_test_utils::NavigateToURL(browser(), url1);
+ browser()->AddTabWithURL(url2, GURL(), PageTransition::LINK, 1,
+ Browser::ADD_SELECTED, NULL, std::string());
+ ui_test_utils::WaitForNavigationInCurrentTab(browser());
+
+ browser()->AddTabWithURL(url3, GURL(), PageTransition::LINK, 2,
+ Browser::ADD_SELECTED, NULL, std::string());
+ ui_test_utils::WaitForNavigationInCurrentTab(browser());
+
+ TabRestoreService* service = browser()->profile()->GetTabRestoreService();
+ service->ClearEntries();
+
+ browser()->window()->Close();
+
+ // Expect a window with three tabs.
+ EXPECT_EQ(1U, service->entries().size());
+ ASSERT_EQ(TabRestoreService::WINDOW, service->entries().front()->type);
+ const TabRestoreService::Window* window =
+ static_cast<TabRestoreService::Window*>(service->entries().front());
+ EXPECT_EQ(3U, window->tabs.size());
+
+ // Find the SessionID for entry2. Since the session service was destroyed,
+ // there is no guarantee that the SessionID for the tab has remained the same.
+ std::vector<TabRestoreService::Tab>::const_iterator it = window->tabs.begin();
+ for ( ; it != window->tabs.end(); ++it) {
+ const TabRestoreService::Tab& tab = *it;
+ // If this tab held url2, then restore this single tab.
+ if (tab.navigations[0].virtual_url() == url2) {
+ service->RestoreEntryById(NULL, tab.id, false);
+ break;
+ }
+ }
+
+ // Make sure that the Window got updated.
+ EXPECT_EQ(1U, service->entries().size());
+ ASSERT_EQ(TabRestoreService::WINDOW, service->entries().front()->type);
+ window = static_cast<TabRestoreService::Window*>(service->entries().front());
+ EXPECT_EQ(2U, window->tabs.size());
+}
+
diff --git a/chrome/browser/sessions/tab_restore_service.cc b/chrome/browser/sessions/tab_restore_service.cc
index 0559de5..1c0f064 100644
--- a/chrome/browser/sessions/tab_restore_service.cc
+++ b/chrome/browser/sessions/tab_restore_service.cc
@@ -112,13 +112,33 @@ typedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry;
void RemoveEntryByID(SessionID::id_type id,
IDToEntry* id_to_entry,
std::vector<TabRestoreService::Entry*>* entries) {
+ // Look for the entry in the map. If it is present, erase it from both
+ // collections and return.
IDToEntry::iterator i = id_to_entry->find(id);
- if (i == id_to_entry->end())
+ if (i != id_to_entry->end()) {
+ entries->erase(std::find(entries->begin(), entries->end(), i->second));
+ delete i->second;
+ id_to_entry->erase(i);
return;
+ }
- entries->erase(std::find(entries->begin(), entries->end(), i->second));
- delete i->second;
- id_to_entry->erase(i);
+ // Otherwise, loop over all items in the map and see if any of the Windows
+ // have Tabs with the |id|.
+ for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end();
+ ++i) {
+ if (i->second->type == TabRestoreService::WINDOW) {
+ TabRestoreService::Window* window =
+ static_cast<TabRestoreService::Window*>(i->second);
+ std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin();
+ for ( ; j != window->tabs.end(); ++j) {
+ // If the ID matches one of this window's tabs, remove it from the list.
+ if ((*j).id == id) {
+ window->tabs.erase(j);
+ return;
+ }
+ }
+ }
+ }
}
} // namespace
@@ -262,64 +282,75 @@ void TabRestoreService::RestoreEntryById(Browser* browser,
restoring_ = true;
Entry* entry = *i;
- entries_.erase(i);
- i = entries_.end();
+
+ // If the entry's ID does not match the ID that is being restored, then the
+ // entry is a window from which a single tab will be restored.
+ bool restoring_tab_in_window = entry->id != id;
+
+ if (!restoring_tab_in_window) {
+ entries_.erase(i);
+ i = entries_.end();
+ }
// |browser| will be NULL in cases where one isn't already available (eg,
// when invoked on Mac OS X with no windows open). In this case, create a
// new browser into which we restore the tabs.
if (entry->type == TAB) {
Tab* tab = static_cast<Tab*>(entry);
- if (replace_existing_tab && browser) {
- browser->ReplaceRestoredTab(tab->navigations,
- tab->current_navigation_index,
- tab->from_last_session,
- tab->extension_app_id);
+ browser = RestoreTab(*tab, browser, replace_existing_tab);
+ } else if (entry->type == WINDOW) {
+ Browser* current_browser = browser;
+ Window* window = static_cast<Window*>(entry);
+
+ // When restoring a window, either the entire window can be restored, or a
+ // single tab within it. If the entry's ID matches the one to restore, then
+ // the entire window will be restored.
+ if (!restoring_tab_in_window) {
+ browser = Browser::Create(profile());
+ for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) {
+ const Tab& tab = window->tabs[tab_i];
+ TabContents* restored_tab =
+ browser->AddRestoredTab(tab.navigations, browser->tab_count(),
+ tab.current_navigation_index,
+ tab.extension_app_id,
+ (static_cast<int>(tab_i) ==
+ window->selected_tab_index),
+ tab.pinned, tab.from_last_session);
+ if (restored_tab)
+ restored_tab->controller().LoadIfNecessary();
+ }
+ // All the window's tabs had the same former browser_id.
+ if (window->tabs[0].has_browser()) {
+ UpdateTabBrowserIDs(window->tabs[0].browser_id,
+ browser->session_id().id());
+ }
} else {
- // 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::Create(profile());
- if (tab->has_browser()) {
- UpdateTabBrowserIDs(tab->browser_id,
- tab_browser->session_id().id());
+ // Restore a single tab from the window. Find the tab that matches the ID
+ // in the window and restore it.
+ for (std::vector<Tab>::iterator tab_i = window->tabs.begin();
+ tab_i != window->tabs.end(); ++tab_i) {
+ const Tab& tab = *tab_i;
+ if (tab.id == id) {
+ browser = RestoreTab(tab, browser, replace_existing_tab);
+ window->tabs.erase(tab_i);
+ // If restoring the tab leaves the window with nothing else, delete it
+ // as well.
+ if (!window->tabs.size()) {
+ entries_.erase(i);
+ delete entry;
+ } else {
+ // Update the browser ID of the rest of the tabs in the window so if
+ // any one is restored, it goes into the same window as the tab
+ // being restored now.
+ for (std::vector<Tab>::iterator tab_j = window->tabs.begin();
+ tab_j != window->tabs.end(); ++tab_j) {
+ UpdateTabBrowserIDs((*tab_j).browser_id,
+ browser->session_id().id());
+ }
+ }
+ break;
}
- tab_browser->window()->Show();
}
-
- if (tab_index < 0 || tab_index > tab_browser->tab_count())
- tab_index = tab_browser->tab_count();
- tab_browser->AddRestoredTab(tab->navigations, tab_index,
- tab->current_navigation_index,
- tab->extension_app_id, true, tab->pinned,
- tab->from_last_session);
- }
- } else if (entry->type == WINDOW) {
- Browser* current_browser = browser;
- const Window* window = static_cast<Window*>(entry);
- browser = Browser::Create(profile());
- for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) {
- const Tab& tab = window->tabs[tab_i];
- TabContents* restored_tab =
- browser->AddRestoredTab(tab.navigations, browser->tab_count(),
- tab.current_navigation_index,
- tab.extension_app_id,
- (static_cast<int>(tab_i) ==
- window->selected_tab_index),
- tab.pinned, tab.from_last_session);
- if (restored_tab)
- restored_tab->controller().LoadIfNecessary();
- }
- // All the window's tabs had the same former browser_id.
- if (window->tabs[0].has_browser()) {
- UpdateTabBrowserIDs(window->tabs[0].browser_id,
- browser->session_id().id());
}
browser->window()->Show();
@@ -331,7 +362,10 @@ void TabRestoreService::RestoreEntryById(Browser* browser,
NOTREACHED();
}
- delete entry;
+ if (!restoring_tab_in_window) {
+ delete entry;
+ }
+
restoring_ = false;
NotifyTabsChanged();
}
@@ -458,6 +492,18 @@ TabRestoreService::Entries::iterator TabRestoreService::GetEntryIteratorById(
for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) {
if ((*i)->id == id)
return i;
+
+ // For Window entries, see if the ID matches a tab. If so, report the window
+ // as the Entry.
+ if ((*i)->type == WINDOW) {
+ std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs;
+ for (std::vector<Tab>::iterator j = tabs.begin();
+ j != tabs.end(); ++j) {
+ if ((*j).id == id) {
+ return i;
+ }
+ }
+ }
}
return entries_.end();
}
@@ -785,6 +831,45 @@ void TabRestoreService::CreateEntriesFromCommands(
loaded_entries->swap(entries.get());
}
+Browser* TabRestoreService::RestoreTab(const Tab& tab,
+ Browser* browser,
+ bool replace_existing_tab) {
+ // |browser| will be NULL in cases where one isn't already available (eg,
+ // when invoked on Mac OS X with no windows open). In this case, create a
+ // new browser into which we restore the tabs.
+ if (replace_existing_tab && browser) {
+ browser->ReplaceRestoredTab(tab.navigations,
+ tab.current_navigation_index,
+ tab.from_last_session,
+ tab.extension_app_id);
+ } else {
+ if (tab.has_browser())
+ browser = BrowserList::FindBrowserWithID(tab.browser_id);
+
+ int tab_index = -1;
+ if (browser) {
+ tab_index = tab.tabstrip_index;
+ } else {
+ browser = Browser::Create(profile());
+ if (tab.has_browser()) {
+ UpdateTabBrowserIDs(tab.browser_id, browser->session_id().id());
+ }
+ }
+
+ if (tab_index < 0 || tab_index > browser->tab_count()) {
+ tab_index = browser->tab_count();
+ }
+
+ browser->AddRestoredTab(tab.navigations,
+ tab_index,
+ tab.current_navigation_index,
+ tab.extension_app_id,
+ true, tab.pinned, tab.from_last_session);
+ }
+ return browser;
+}
+
+
bool TabRestoreService::ValidateTab(Tab* tab) {
if (tab->navigations.empty())
return false;
diff --git a/chrome/browser/sessions/tab_restore_service.h b/chrome/browser/sessions/tab_restore_service.h
index 9e81722..bab699a 100644
--- a/chrome/browser/sessions/tab_restore_service.h
+++ b/chrome/browser/sessions/tab_restore_service.h
@@ -211,7 +211,10 @@ class TabRestoreService : public BaseSessionService {
// Prunes entries_ to contain only kMaxEntries and invokes NotifyTabsChanged.
void PruneAndNotify();
- // Returns an iterator into entries_ whose id matches |id|.
+ // Returns an iterator into entries_ whose id matches |id|. If |id| identifies
+ // a Window, then its iterator position will be returned. If it identifies a
+ // tab, then the iterator position of the Window in which the Tab resides is
+ // returned.
Entries::iterator GetEntryIteratorById(SessionID::id_type id);
// Schedules the commands for a window close.
@@ -254,6 +257,14 @@ class TabRestoreService : public BaseSessionService {
scoped_refptr<InternalGetCommandsRequest> request,
std::vector<Entry*>* loaded_entries);
+ // This is a helper function for RestoreEntryById() for restoring a single
+ // tab. If |replace_existing_tab| is true, the newly created tab replaces the
+ // selected tab in |browser|. If |browser| is NULL, this creates a new window
+ // for the entry. This returns the Browser into which the tab was restored.
+ Browser* RestoreTab(const Tab& tab,
+ Browser* browser,
+ bool replace_existing_tab);
+
// Returns true if |tab| has more than one navigation. If |tab| has more
// than one navigation |tab->current_navigation_index| is constrained based
// on the number of navigations.