blob: 9704e6a14e92329d8021fceea46a6a1de5123222 [file] [log] [blame]
// 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<ListValue> 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<TabRestoreService::Tab> tab_entry(
tab_restore_service_->RemoveTabEntryById(static_cast<int>(
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<int>(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<int>(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<DictionaryValue> entry_dict(new DictionaryValue());
if (entry->type == TabRestoreService::TAB) {
TabToValue(*static_cast<TabRestoreService::Tab*>(entry),
entry_dict.get());
} else {
DCHECK_EQ(entry->type, TabRestoreService::WINDOW);
WindowToValue(*static_cast<TabRestoreService::Window*>(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);
}
}