diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-18 17:12:27 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-18 17:12:27 +0000 |
commit | f74d445459f6bf0479acc08c9c851c12540e6986 (patch) | |
tree | 8096e61b722ccf0aa0cbdb724353c8d154963802 /chrome | |
parent | 06a7a1a48f1d70b0b47f7014d73680e2a520a13f (diff) | |
download | chromium_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.cc | 56 | ||||
-rw-r--r-- | chrome/browser/sessions/tab_restore_service.cc | 193 | ||||
-rw-r--r-- | chrome/browser/sessions/tab_restore_service.h | 13 |
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. |