diff options
author | sky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-25 22:45:39 +0000 |
---|---|---|
committer | sky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-25 22:45:39 +0000 |
commit | d8375fdbe8d32ad3562152ecd53378383e393971 (patch) | |
tree | 8c8f3e524fb5e600095368e982e5730916259453 /chrome/browser | |
parent | ec9f22cd4e7151ab3c3eb6ba47885bd75d342ae3 (diff) | |
download | chromium_src-d8375fdbe8d32ad3562152ecd53378383e393971.zip chromium_src-d8375fdbe8d32ad3562152ecd53378383e393971.tar.gz chromium_src-d8375fdbe8d32ad3562152ecd53378383e393971.tar.bz2 |
Changes tab restore service to handle restoring closed windows as a
single unit. Sadly I've written another ui test. Lets hope it isn't
flakey. Glen is going to change the NTP to deal with this appropriately.
BUG=4686
TEST=Try closing a window (with more than one window open), hitting
control-shift-t, and make sure the window and all it's tabs comes
back.
Review URL: http://codereview.chromium.org/11377
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6003 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser.cc | 22 | ||||
-rw-r--r-- | chrome/browser/browsing_data_remover.cc | 2 | ||||
-rw-r--r-- | chrome/browser/dom_ui/new_tab_ui.cc | 98 | ||||
-rw-r--r-- | chrome/browser/dom_ui/new_tab_ui.h | 10 | ||||
-rw-r--r-- | chrome/browser/tab_restore_service.cc | 212 | ||||
-rw-r--r-- | chrome/browser/tab_restore_service.h | 155 | ||||
-rw-r--r-- | chrome/browser/tab_restore_uitest.cc | 54 |
7 files changed, 340 insertions, 213 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index efacd90..a8cc944 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -189,6 +189,10 @@ Browser::~Browser() { if (session_service) session_service->WindowClosed(session_id_); + TabRestoreService* tab_restore_service = profile()->GetTabRestoreService(); + if (tab_restore_service) + tab_restore_service->BrowserClosed(this); + NotificationService::current()->RemoveObserver( this, NOTIFY_SSL_STATE_CHANGED, NotificationService::AllSources()); @@ -439,6 +443,10 @@ void Browser::OnWindowClosing() { if (session_service) session_service->WindowClosing(session_id()); + TabRestoreService* tab_restore_service = profile()->GetTabRestoreService(); + if (tab_restore_service) + tab_restore_service->BrowserClosing(this); + CloseAllTabs(); } @@ -689,14 +697,7 @@ void Browser::RestoreTab() { if (!service) return; - const TabRestoreService::Tabs& tabs = service->tabs(); - if (tabs.empty() || tabs.front().from_last_session) - return; - - const TabRestoreService::HistoricalTab& tab = tabs.front(); - AddRestoredTab(tab.navigations, tab_count(), tab.current_navigation_index, - true); - service->RemoveHistoricalTabById(tab.id); + service->RestoreMostRecentEntry(this); } void Browser::ConvertPopupToTabbedBrowser() { @@ -1950,6 +1951,11 @@ void Browser::InitCommandState() { void Browser::UpdateNavigationCommands() { TabContents* current_tab = GetSelectedTabContents(); + if (!current_tab) { + // It's possible for this to be null during tab restore. + return; + } + NavigationController* nc = current_tab->controller(); controller_.UpdateCommandEnabled(IDC_BACK, nc->CanGoBack()); controller_.UpdateCommandEnabled(IDC_FORWARD, nc->CanGoForward()); diff --git a/chrome/browser/browsing_data_remover.cc b/chrome/browser/browsing_data_remover.cc index 41aa9ae..e0cdc68 100644 --- a/chrome/browser/browsing_data_remover.cc +++ b/chrome/browser/browsing_data_remover.cc @@ -78,7 +78,7 @@ void BrowsingDataRemover::Remove(int remove_mask) { // they can't be more than a day old, so we can simply clear them all. TabRestoreService* tab_service = profile_->GetTabRestoreService(); if (tab_service) - tab_service->ClearHistoricalTabs(); + tab_service->ClearEntries(); // We also delete the last session when we delete the history. SessionService* session_service = profile_->GetSessionService(); diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc index 729c9dc..5a87b2d 100644 --- a/chrome/browser/dom_ui/new_tab_ui.cc +++ b/chrome/browser/dom_ui/new_tab_ui.cc @@ -644,20 +644,10 @@ void RecentlyClosedTabsHandler::HandleReopenTab(const Value* content) { std::wstring wstring_value; if (string_value->GetAsString(&wstring_value)) { int session_to_restore = _wtoi(wstring_value.c_str()); - - const TabRestoreService::Tabs& tabs = tab_restore_service_->tabs(); - for (TabRestoreService::Tabs::const_iterator it = tabs.begin(); - it != tabs.end(); ++it) { - if (it->id == session_to_restore) { - TabRestoreService* tab_restore_service = tab_restore_service_; - browser->ReplaceRestoredTab( - it->navigations, it->current_navigation_index); - tab_restore_service->RemoveHistoricalTabById(session_to_restore); - // The current tab has been nuked at this point; - // don't touch any member variables. - break; - } - } + tab_restore_service_->RestoreEntryById(browser, session_to_restore, + true); + // The current tab has been nuked at this point; don't touch any member + // variables. } } } @@ -680,28 +670,28 @@ void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs( void RecentlyClosedTabsHandler::TabRestoreServiceChanged( TabRestoreService* service) { - const TabRestoreService::Tabs& tabs = service->tabs(); + const TabRestoreService::Entries& entries = service->entries(); ListValue list_value; int added_count = 0; - // We filter the list of recently closed to only show 'interesting' tabs, - // where an interesting tab navigation is not the new tab ui. - for (TabRestoreService::Tabs::const_iterator it = tabs.begin(); - it != tabs.end() && added_count < 3; ++it) { - if (it->navigations.empty()) - continue; - - const TabNavigation& navigator = - it->navigations.at(it->current_navigation_index); - if (navigator.url == NewTabUIURL()) - continue; - - DictionaryValue* dictionary = new DictionaryValue; - SetURLAndTitle(dictionary, navigator.title, navigator.url); - dictionary->SetInteger(L"sessionId", it->id); - - list_value.Append(dictionary); - added_count++; + // We filter the list of recently closed to only show 'interesting' entries, + // where an interesting entry is either a closed window or a closed tab + // whose selected navigation is not the new tab ui. + for (TabRestoreService::Entries::const_iterator it = entries.begin(); + it != entries.end() && added_count < 3; ++it) { + TabRestoreService::Entry* entry = *it; + DictionaryValue* value = new DictionaryValue(); + if ((entry->type == TabRestoreService::TAB && + TabToValue(*static_cast<TabRestoreService::Tab*>(entry), value)) || + (entry->type == TabRestoreService::WINDOW && + WindowToValue(*static_cast<TabRestoreService::Window*>(entry), + value))) { + value->SetInteger(L"sessionId", entry->id); + list_value.Append(value); + added_count++; + } else { + delete value; + } } dom_ui_host_->CallJavascriptFunction(L"recentlyClosedTabs", list_value); } @@ -711,6 +701,48 @@ void RecentlyClosedTabsHandler::TabRestoreServiceDestroyed( tab_restore_service_ = NULL; } +bool RecentlyClosedTabsHandler::TabToValue( + const TabRestoreService::Tab& tab, + DictionaryValue* dictionary) { + if (tab.navigations.empty()) + return false; + + const TabNavigation& current_navigation = + tab.navigations.at(tab.current_navigation_index); + if (current_navigation.url == NewTabUIURL()) + return false; + + SetURLAndTitle(dictionary, current_navigation.title, current_navigation.url); + dictionary->SetString(L"type", L"tab"); + return true; +} + +bool RecentlyClosedTabsHandler::WindowToValue( + const TabRestoreService::Window& window, + DictionaryValue* dictionary) { + if (window.tabs.empty()) { + NOTREACHED(); + return false; + } + + ListValue* tab_values = new ListValue(); + for (size_t i = 0; i < window.tabs.size(); ++i) { + DictionaryValue* tab_value = new DictionaryValue(); + if (TabToValue(window.tabs[i], tab_value)) + tab_values->Append(tab_value); + else + delete tab_value; + } + if (tab_values->GetSize() == 0) { + delete tab_values; + return false; + } + + dictionary->SetString(L"type", L"window"); + dictionary->Set(L"tabs", tab_values); + return true; +} + /////////////////////////////////////////////////////////////////////////////// // HistoryHandler diff --git a/chrome/browser/dom_ui/new_tab_ui.h b/chrome/browser/dom_ui/new_tab_ui.h index ed31cde..814e73a 100644 --- a/chrome/browser/dom_ui/new_tab_ui.h +++ b/chrome/browser/dom_ui/new_tab_ui.h @@ -263,6 +263,16 @@ class RecentlyClosedTabsHandler : public DOMMessageHandler, virtual void TabRestoreServiceDestroyed(TabRestoreService* service); private: + // Converts a closed tab to the value sent down to the NTP. Returns true on + // success, false if the value shouldn't be sent down. + bool TabToValue(const TabRestoreService::Tab& tab, + DictionaryValue* dictionary); + + // Converts a closed window to the value sent down to the NTP. Returns true + // on success, false if the value shouldn't be sent down. + bool WindowToValue(const TabRestoreService::Window& window, + DictionaryValue* dictionary); + DOMUIHost* dom_ui_host_; /// TabRestoreService that we are observing. diff --git a/chrome/browser/tab_restore_service.cc b/chrome/browser/tab_restore_service.cc index 4fcbe8c..bc8b9c7 100644 --- a/chrome/browser/tab_restore_service.cc +++ b/chrome/browser/tab_restore_service.cc @@ -4,40 +4,37 @@ #include "chrome/browser/tab_restore_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/browser_list.h" #include "chrome/browser/navigation_controller.h" #include "chrome/browser/navigation_entry.h" +#include "chrome/browser/profile.h" +#include "chrome/common/stl_util-inl.h" using base::Time; -// HistoricalTab -------------------------------------------------------------- +// Entry ---------------------------------------------------------------------- -// ID of the next HistoricalTab. -static int next_historical_tab_id = 1; +// ID of the next Entry. +static int next_entry_id = 1; -TabRestoreService::HistoricalTab::HistoricalTab() - : close_time(Time::Now()), - from_last_session(false), - current_navigation_index(-1), - id(next_historical_tab_id++) { -} +TabRestoreService::Entry::Entry() : id(next_entry_id++), type(TAB) {} -// TabRestoreService ---------------------------------------------------------- +TabRestoreService::Entry::Entry(Type type) : id(next_entry_id++), type(type) {} -// Max number of tabs we'll keep around. -static const size_t kMaxTabs = 10; +// TabRestoreService ---------------------------------------------------------- -// Amount of time from when the session starts and when we'll allow loading of -// the last sessions tabs. -static const int kLoadFromLastSessionMS = 600000; +// Max number of entries we'll keep around. +static const size_t kMaxEntries = 10; TabRestoreService::TabRestoreService(Profile* profile) : profile_(profile), - loaded_last_session_(false) { + loaded_last_session_(false), + restoring_(false) { } TabRestoreService::~TabRestoreService() { FOR_EACH_OBSERVER(Observer, observer_list_, TabRestoreServiceDestroyed(this)); + STLDeleteElements(&entries_); } void TabRestoreService::AddObserver(Observer* observer) { @@ -48,107 +45,112 @@ void TabRestoreService::RemoveObserver(Observer* observer) { observer_list_.RemoveObserver(observer); } -void TabRestoreService::LoadPreviousSessionTabs() { - if (!WillLoadPreviousSessionTabs() || IsLoadingPreviousSessionTabs()) +void TabRestoreService::CreateHistoricalTab(NavigationController* tab) { + if (restoring_) return; - profile_->GetSessionService()->GetLastSession( - &cancelable_consumer_, - NewCallback(this, &TabRestoreService::OnGotLastSession)); -} + Browser* browser = Browser::GetBrowserForController(tab, NULL); + if (closing_browsers_.find(browser) != closing_browsers_.end()) + return; -bool TabRestoreService::IsLoadingPreviousSessionTabs() { - return cancelable_consumer_.HasPendingRequests(); -} + Tab* local_tab = new Tab(); + PopulateTabFromController(tab, local_tab); + entries_.push_front(local_tab); -bool TabRestoreService::WillLoadPreviousSessionTabs() { - return (!loaded_last_session_ && tabs_.size() < kMaxTabs && - (Time::Now() - profile_->GetStartTime()).InMilliseconds() < - kLoadFromLastSessionMS); + PruneAndNotify(); } -void TabRestoreService::CreateHistoricalTab(NavigationController* tab) { - tabs_.push_front(HistoricalTab()); - - PopulateTabFromController(tab, &(tabs_.front())); - - while (tabs_.size() > kMaxTabs) - tabs_.pop_back(); +void TabRestoreService::BrowserClosing(Browser* browser) { + if (browser->type() != Browser::TYPE_NORMAL || + browser->tab_count() == 0) + return; - NotifyTabsChanged(); + closing_browsers_.insert(browser); + + Window* window = new Window(); + window->selected_tab_index = browser->selected_index(); + window->tabs.resize(browser->tab_count()); + size_t entry_index = 0; + for (int tab_index = 0; tab_index < browser->tab_count(); ++tab_index) { + PopulateTabFromController( + browser->GetTabContentsAt(tab_index)->controller(), + &(window->tabs[entry_index])); + if (window->tabs[entry_index].navigations.empty()) + window->tabs.erase(window->tabs.begin() + entry_index); + else + entry_index++; + } + if (window->tabs.empty()) { + delete window; + window = NULL; + } else { + entries_.push_front(window); + PruneAndNotify(); + } } -void TabRestoreService::RemoveHistoricalTabById(int id) { - for (Tabs::iterator i = tabs_.begin(); i != tabs_.end(); ++i) { - if (i->id == id) { - tabs_.erase(i); - NotifyTabsChanged(); - return; - } - } - // Don't hoark here, we allow an invalid id. +void TabRestoreService::BrowserClosed(Browser* browser) { + closing_browsers_.erase(browser); } -void TabRestoreService::ClearHistoricalTabs() { - tabs_.clear(); +void TabRestoreService::ClearEntries() { + STLDeleteElements(&entries_); NotifyTabsChanged(); } -void TabRestoreService::OnGotLastSession(SessionService::Handle handle, - std::vector<SessionWindow*>* windows) { - DCHECK(!loaded_last_session_); - loaded_last_session_ = true; - - if (tabs_.size() == kMaxTabs) +void TabRestoreService::RestoreMostRecentEntry(Browser* browser) { + if (entries_.empty()) return; - AddHistoricalTabs(windows); - - NotifyTabsChanged(); + RestoreEntryById(browser, entries_.front()->id, false); } -void TabRestoreService::AddHistoricalTabs( - std::vector<SessionWindow*>* windows) { - // First pass, extract the selected tabs in each window. - for (size_t i = 0; i < windows->size(); ++i) { - SessionWindow* window = (*windows)[i]; - if (window->type == Browser::TYPE_NORMAL) { - DCHECK(window->selected_tab_index >= 0 && - window->selected_tab_index < - static_cast<int>(window->tabs.size())); - AppendHistoricalTabFromSessionTab( - window->tabs[window->selected_tab_index]); - if (tabs_.size() == kMaxTabs) - return; - } +void TabRestoreService::RestoreEntryById(Browser* browser, + int id, + bool replace_existing_tab) { + Entries::iterator i = GetEntryIteratorById(id); + if (i == entries_.end()) { + // Don't hoark here, we allow an invalid id. + return; } - // Second pass, extract the non-selected tabs. - for (size_t window_index = 0; window_index < windows->size(); - ++window_index) { - SessionWindow* window = (*windows)[window_index]; - if (window->type != Browser::TYPE_NORMAL) - continue; // Ignore popups. - - for (size_t tab_index = 0; tab_index < window->tabs.size(); ++tab_index) { - if (tab_index == window->selected_tab_index) - continue; // Pass one took care of this tab. - AppendHistoricalTabFromSessionTab(window->tabs[tab_index]); - if (tabs_.size() == kMaxTabs) - return; + restoring_ = true; + Entry* entry = *i; + entries_.erase(i); + i = entries_.end(); + if (entry->type == TAB) { + Tab* tab = static_cast<Tab*>(entry); + if (replace_existing_tab) { + browser->ReplaceRestoredTab(tab->navigations, + tab->current_navigation_index); + } else { + browser->AddRestoredTab(tab->navigations, browser->tab_count(), + tab->current_navigation_index, true); + } + } else if (entry->type == WINDOW) { + const Window* window = static_cast<Window*>(entry); + Browser* browser = Browser::Create(profile_); + for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) { + const Tab& tab = window->tabs[tab_i]; + NavigationController* restored_controller = + browser->AddRestoredTab(tab.navigations, browser->tab_count(), + tab.current_navigation_index, + (tab_i == window->selected_tab_index)); + if (restored_controller) + restored_controller->LoadIfNecessary(); } + browser->window()->Show(); + } else { + NOTREACHED(); } -} - -void TabRestoreService::AppendHistoricalTabFromSessionTab( - SessionTab* tab) { - tabs_.push_back(HistoricalTab()); - PopulateTabFromSessionTab(tab, &(tabs_.back())); + delete entry; + restoring_ = false; + NotifyTabsChanged(); } void TabRestoreService::PopulateTabFromController( NavigationController* controller, - HistoricalTab* tab) { + Tab* tab) { const int pending_index = controller->GetPendingEntryIndex(); int entry_count = controller->GetEntryCount(); if (entry_count == 0 && pending_index == 0) @@ -171,14 +173,24 @@ void TabRestoreService::PopulateTabFromController( tab->current_navigation_index = 0; } -void TabRestoreService::PopulateTabFromSessionTab( - SessionTab* session_tab, - HistoricalTab* tab) { - tab->navigations.swap(session_tab->navigations); - tab->from_last_session = true; - tab->current_navigation_index = session_tab->current_navigation_index; -} - void TabRestoreService::NotifyTabsChanged() { FOR_EACH_OBSERVER(Observer, observer_list_, TabRestoreServiceChanged(this)); } + +void TabRestoreService::PruneAndNotify() { + while (entries_.size() > kMaxEntries) { + delete entries_.back(); + entries_.pop_back(); + } + + NotifyTabsChanged(); +} + +TabRestoreService::Entries::iterator TabRestoreService::GetEntryIteratorById( + int id) { + for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { + if ((*i)->id == id) + return i; + } + return entries_.end(); +} diff --git a/chrome/browser/tab_restore_service.h b/chrome/browser/tab_restore_service.h index 66157f4..5d1460e 100644 --- a/chrome/browser/tab_restore_service.h +++ b/chrome/browser/tab_restore_service.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_TAB_RESTORE_SERVICE_H__ -#define CHROME_BROWSER_TAB_RESTORE_SERVICE_H__ +#ifndef CHROME_BROWSER_TAB_RESTORE_SERVICE_H_ +#define CHROME_BROWSER_TAB_RESTORE_SERVICE_H_ #include <list> @@ -15,27 +15,23 @@ class NavigationController; class Profile; // TabRestoreService is responsible for maintaining the most recently closed -// tabs. When the user closes a tab TabRestoreService::CreateHistoricalTab is -// invoked and a HistoricalTab is created to represent the tab. +// tabs and windows. When a tab is closed +// TabRestoreService::CreateHistoricalTab is invoked and a Tab is created to +// represent the tab. Similarly, when a browser is closed, BrowserClosing is +// invoked and a Window is created to represent the window. // -// TabRestoreService can recreate tabs from the previous session as well. -// LoadPreviousSessionTabs loads (asynchronously) the tabs from the previous -// session. When done, the observer is notified. +// To restore a tab/window from the TabRestoreService invoke RestoreEntryById +// or RestoreMostRecentEntry. // -// To restore a tab from the TabRestoreService invoke AddRestoredTab on the -// Browser you want to restore the tab to, followed by RemoveHistoricalTabById -// to remove the tab from the restore service. -// -// To listen for changes to the set of tabs managed by the TabRestoreService +// To listen for changes to the set of entries managed by the TabRestoreService // add an observer. - class TabRestoreService { public: - // Observer is notified when the set of tabs managed by TabRestoreService + // Observer is notified when the set of entries managed by TabRestoreService // changes in some way. class Observer { public: - // Sent when the internal tab state changed + // Sent when the set of entries changes in some way. virtual void TabRestoreServiceChanged(TabRestoreService* service) = 0; // Sent to all remaining Observers when TabRestoreService's @@ -43,15 +39,28 @@ class TabRestoreService { virtual void TabRestoreServiceDestroyed(TabRestoreService* service) = 0; }; - // Represents a previously open tab. - struct HistoricalTab { - HistoricalTab(); + // The type of entry. + enum Type { + TAB, + WINDOW + }; + + struct Entry { + Entry(); + explicit Entry(Type type); + virtual ~Entry() {} + + // Unique id for this entry. The id is guaranteed to be unique for a + // session. + int id; - // Time the tab was closed. - base::Time close_time; + // The type of the entry. + Type type; + }; - // If true, this is a historical session and not a closed tab. - bool from_last_session; + // Represents a previously open tab. + struct Tab : public Entry { + Tab() : Entry(TAB), current_navigation_index(-1) {} // The navigations. // WARNING: navigations may be empty. @@ -59,16 +68,22 @@ class TabRestoreService { // Index of the selected navigation in navigations. int current_navigation_index; + }; - // Unique id for the closed tab. This is guaranteed to be unique for - // a session. - const int id; + // Represents a previously open window. + struct Window : public Entry { + Window() : Entry(WINDOW), selected_tab_index(-1) {} + + // The tabs that comprised the window, in order. + std::vector<Tab> tabs; + + // Index of the selected tab. + int selected_tab_index; }; - typedef std::list<HistoricalTab> Tabs; + typedef std::list<Entry*> Entries; - // Creates a new TabRestoreService. This does not load tabs from the last - // session, you must explicitly invoke LoadPreviousSessionTabs to do that. + // Creates a new TabRestoreService. explicit TabRestoreService(Profile* profile); ~TabRestoreService(); @@ -77,70 +92,70 @@ class TabRestoreService { void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); - // If the previous session has not been loaded, it is loaded and the tabs - // from it are placed at the end of the queue. - void LoadPreviousSessionTabs(); - - // Returns true if loading the previous sessions tabs. - bool IsLoadingPreviousSessionTabs(); - - // Returns true if LoadPreviousSessionTabs will attempt to load any tabs. - bool WillLoadPreviousSessionTabs(); - - // Creates a HistoricalTab to represent the tab and notifies observers the - // list of tabs has changed. + // Creates a Tab to represent |tab| and notifies observers the list of + // entries has changed. void CreateHistoricalTab(NavigationController* tab); - // Removes the HistoricalTab with the specified id and notifies observers. - // Does nothing if id does not identify a valid historical tab id. - void RemoveHistoricalTabById(int id); + // Invoked when a browser is closing. If |browser| is a tabbed browser with + // at least one tab, a Window is created, added to entries and observers are + // notified. + void BrowserClosing(Browser* browser); - // Removes all HistoricalTabs from the list and notifies observers the list - // of tabs has changed. - void ClearHistoricalTabs(); + // Invoked when the browser is done closing. + void BrowserClosed(Browser* browser); - // Returns the tabs, ordered with most recently closed tabs at the front. - const Tabs& tabs() const { return tabs_; } + // Removes all entries from the list and notifies observers the list + // of tabs has changed. + void ClearEntries(); - private: - // Callback from loading the last session. As necessary adds the tabs to - // tabs_. - void OnGotLastSession(SessionService::Handle handle, - std::vector<SessionWindow*>* windows); + // Returns the entries, ordered with most recently closed entries at the + // front. + const Entries& entries() const { return entries_; } - // Invoked from OnGotLastSession to add the necessary tabs from windows - // to tabs_. - void AddHistoricalTabs(std::vector<SessionWindow*>* windows); + // Restores the most recently closed entry. Does nothing if there are no + // entries to restore. If the most recently restored entry is a tab, it is + // added to |browser|. + void RestoreMostRecentEntry(Browser* browser); - // Creates a HistoricalTab from the tab. - void AppendHistoricalTabFromSessionTab(SessionTab* tab); + // Restores an entry by id. If there is no entry with an id matching |id|, + // this does nothing. If |replace_existing_tab| is true and id identifies a + // tab, the newly created tab replaces the selected tab in |browser|. + void RestoreEntryById(Browser* browser, int id, bool replace_existing_tab); + private: // Populates tabs->navigations from the NavigationController. void PopulateTabFromController(NavigationController* controller, - HistoricalTab* tab); - - // Populates tab->navigations from a previous sessions navigations. - void PopulateTabFromSessionTab(SessionTab* session_tab, - HistoricalTab* tab); + Tab* tab); // Notifies observers the tabs have changed. void NotifyTabsChanged(); + // Prunes entries_ to contain only kMaxEntries and invokes NotifyTabsChanged. + void PruneAndNotify(); + + // Returns an iterator into entries_ whose id matches |id|. + Entries::iterator GetEntryIteratorById(int id); + Profile* profile_; // Whether we've loaded the last session. bool loaded_last_session_; - // Set of tabs. We own the NavigationControllers in this list. - Tabs tabs_; + // Set of entries. + Entries entries_; - // Used in requesting the last session. - CancelableRequestConsumer cancelable_consumer_; + // Are we restoring a tab? If this is true we ignore requests to create a + // historical tab. + bool restoring_; ObserverList<Observer> observer_list_; - DISALLOW_EVIL_CONSTRUCTORS(TabRestoreService); -}; + // Set of tabs that we've received a BrowserClosing method for but no + // corresponding BrowserClosed. We cache the set of browsers closing to + // avoid creating historical tabs for them. + std::set<Browser*> closing_browsers_; -#endif // CHROME_BROWSER_TAB_RESTORE_SERVICE_H__ + DISALLOW_COPY_AND_ASSIGN(TabRestoreService); +}; +#endif // CHROME_BROWSER_TAB_RESTORE_SERVICE_H_ diff --git a/chrome/browser/tab_restore_uitest.cc b/chrome/browser/tab_restore_uitest.cc index 7a55257..d108d0f 100644 --- a/chrome/browser/tab_restore_uitest.cc +++ b/chrome/browser/tab_restore_uitest.cc @@ -170,7 +170,6 @@ TEST_F(TabRestoreUITest, RestoreWithExistingSiteInstance) { ASSERT_EQ(http_url1, GetActiveTabURL()); } - // Tests that the SiteInstances used for entries in a restored tab's history // are given appropriate max page IDs, even if the renderer for the entry // already exists. (Bug 1204135) @@ -222,3 +221,56 @@ TEST_F(TabRestoreUITest, RestoreCrossSiteWithExistingSiteInstance) { ASSERT_EQ(http_url2, GetActiveTabURL()); } +TEST_F(TabRestoreUITest, RestoreWindow) { + // Create a new window. + int window_count; + ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count)); + ASSERT_TRUE(automation()->OpenNewBrowserWindow(SW_HIDE)); + ASSERT_TRUE(automation()->WaitForWindowCountToBecome(++window_count, + kWaitForActionMaxMsec)); + + // Create two more tabs, one with url1, the other url2. + scoped_ptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); + int initial_tab_count; + ASSERT_TRUE(browser_proxy->GetTabCount(&initial_tab_count)); + browser_proxy->AppendTab(url1_); + ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(initial_tab_count + 1, + kWaitForActionMaxMsec)); + scoped_ptr<TabProxy> new_tab(browser_proxy->GetTab(initial_tab_count)); + new_tab->NavigateToURL(url1_); + browser_proxy->AppendTab(url2_); + ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(initial_tab_count + 2, + kWaitForActionMaxMsec)); + new_tab.reset(browser_proxy->GetTab(initial_tab_count + 1)); + new_tab->NavigateToURL(url2_); + + // Close the window. + ASSERT_TRUE(browser_proxy->ApplyAccelerator(IDC_CLOSEWINDOW)); + browser_proxy.reset(); + new_tab.reset(); + ASSERT_TRUE(automation()->WaitForWindowCountToBecome(window_count - 1, + kWaitForActionMaxMsec)); + + // Restore the window. + browser_proxy.reset(automation()->GetBrowserWindow(0)); + ASSERT_TRUE(browser_proxy->ApplyAccelerator(IDC_RESTORE_TAB)); + ASSERT_TRUE(automation()->WaitForWindowCountToBecome(window_count, + kWaitForActionMaxMsec)); + + browser_proxy.reset(automation()->GetBrowserWindow(1)); + ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(initial_tab_count + 2, + kWaitForActionMaxMsec)); + + scoped_ptr<TabProxy> restored_tab_proxy( + browser_proxy->GetTab(initial_tab_count)); + ASSERT_TRUE(restored_tab_proxy->WaitForTabToBeRestored(kWaitForActionMsec)); + GURL url; + ASSERT_TRUE(restored_tab_proxy->GetCurrentURL(&url)); + ASSERT_TRUE(url == url1_); + + restored_tab_proxy.reset( + browser_proxy->GetTab(initial_tab_count + 1)); + ASSERT_TRUE(restored_tab_proxy->WaitForTabToBeRestored(kWaitForActionMsec)); + ASSERT_TRUE(restored_tab_proxy->GetCurrentURL(&url)); + ASSERT_TRUE(url == url2_); +} |