// Copyright (c) 2012 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/ui/webui/ntp/recently_closed_tabs_handler.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/metrics/histogram.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/tab_restore_service_delegate.h" #include "chrome/browser/sessions/tab_restore_service_factory.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/webui/ntp/new_tab_ui.h" #include "chrome/common/url_constants.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_view.h" #include "content/public/browser/web_ui.h" #include "ui/base/webui/web_ui_util.h" #if defined(OS_ANDROID) #include "chrome/browser/sessions/session_restore.h" #endif namespace { void TabToValue(const TabRestoreService::Tab& tab, DictionaryValue* dictionary) { const sessions::SerializedNavigationEntry& current_navigation = tab.navigations.at(tab.current_navigation_index); NewTabUI::SetUrlTitleAndDirection(dictionary, current_navigation.title(), current_navigation.virtual_url()); dictionary->SetString("type", "tab"); dictionary->SetDouble("timestamp", tab.timestamp.ToDoubleT()); } void WindowToValue(const TabRestoreService::Window& window, DictionaryValue* dictionary) { DCHECK(!window.tabs.empty()); scoped_ptr tab_values(new ListValue()); for (size_t i = 0; i < window.tabs.size(); ++i) { DictionaryValue* tab_value = new DictionaryValue(); TabToValue(window.tabs[i], tab_value); tab_values->Append(tab_value); } dictionary->SetString("type", "window"); dictionary->SetDouble("timestamp", window.timestamp.ToDoubleT()); dictionary->Set("tabs", tab_values.release()); } } // namespace void RecentlyClosedTabsHandler::RegisterMessages() { web_ui()->RegisterMessageCallback("getRecentlyClosedTabs", base::Bind(&RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs, base::Unretained(this))); web_ui()->RegisterMessageCallback("reopenTab", base::Bind(&RecentlyClosedTabsHandler::HandleReopenTab, base::Unretained(this))); web_ui()->RegisterMessageCallback("clearRecentlyClosed", base::Bind(&RecentlyClosedTabsHandler::HandleClearRecentlyClosed, base::Unretained(this))); } RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() { if (tab_restore_service_) tab_restore_service_->RemoveObserver(this); } void RecentlyClosedTabsHandler::HandleReopenTab(const ListValue* args) { if (!tab_restore_service_) return; double session_to_restore = 0.0; CHECK(args->GetDouble(0, &session_to_restore)); #if defined(OS_ANDROID) // Find and remove the corresponding tab entry from TabRestoreService. // We take ownership of the returned tab. scoped_ptr tab_entry( tab_restore_service_->RemoveTabEntryById(static_cast( session_to_restore))); if (tab_entry.get() == NULL) return; // RestoreForeignSessionTab needs a SessionTab. SessionTab session_tab; session_tab.current_navigation_index = tab_entry->current_navigation_index; session_tab.navigations = tab_entry->navigations; SessionRestore::RestoreForeignSessionTab(web_ui()->GetWebContents(), session_tab, NEW_FOREGROUND_TAB); #else double index = -1.0; CHECK(args->GetDouble(1, &index)); // There are actually less than 20 restore tab items displayed in the UI. UMA_HISTOGRAM_ENUMERATION("NewTabPage.SessionRestore", static_cast(index), 20); TabRestoreServiceDelegate* delegate = TabRestoreServiceDelegate::FindDelegateForWebContents( web_ui()->GetWebContents()); if (!delegate) return; chrome::HostDesktopType host_desktop_type = chrome::GetHostDesktopTypeForNativeView( web_ui()->GetWebContents()->GetView()->GetNativeView()); WindowOpenDisposition disposition = webui::GetDispositionFromClick(args, 2); tab_restore_service_->RestoreEntryById(delegate, static_cast(session_to_restore), host_desktop_type, disposition); // The current tab has been nuked at this point; don't touch any member // variables. #endif } void RecentlyClosedTabsHandler::HandleClearRecentlyClosed( const ListValue* args) { EnsureTabRestoreService(); if (tab_restore_service_) tab_restore_service_->ClearEntries(); } void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs( const ListValue* args) { EnsureTabRestoreService(); if (tab_restore_service_) TabRestoreServiceChanged(tab_restore_service_); } void RecentlyClosedTabsHandler::TabRestoreServiceChanged( TabRestoreService* service) { ListValue list_value; TabRestoreService::Entries entries = service->entries(); CreateRecentlyClosedValues(entries, &list_value); web_ui()->CallJavascriptFunction("ntp.setRecentlyClosedTabs", list_value); } void RecentlyClosedTabsHandler::TabRestoreServiceDestroyed( TabRestoreService* service) { tab_restore_service_ = NULL; } // static void RecentlyClosedTabsHandler::CreateRecentlyClosedValues( const TabRestoreService::Entries& entries, ListValue* entry_list_value) { const int max_count = 10; int added_count = 0; // 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 < max_count; ++it) { TabRestoreService::Entry* entry = *it; scoped_ptr entry_dict(new DictionaryValue()); if (entry->type == TabRestoreService::TAB) { TabToValue(*static_cast(entry), entry_dict.get()); } else { DCHECK_EQ(entry->type, TabRestoreService::WINDOW); WindowToValue(*static_cast(entry), entry_dict.get()); } entry_dict->SetInteger("sessionId", entry->id); entry_list_value->Append(entry_dict.release()); ++added_count; } } void RecentlyClosedTabsHandler::EnsureTabRestoreService() { if (tab_restore_service_) return; tab_restore_service_ = TabRestoreServiceFactory::GetForProfile(Profile::FromWebUI(web_ui())); // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in // Off the Record mode) if (tab_restore_service_) { // This does nothing if the tabs have already been loaded or they // shouldn't be loaded. tab_restore_service_->LoadTabsFromLastSession(); tab_restore_service_->AddObserver(this); } }