1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h"
8 #include "base/bind_helpers.h"
9 #include "base/metrics/histogram.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/sessions/tab_restore_service_delegate.h"
12 #include "chrome/browser/sessions/tab_restore_service_factory.h"
13 #include "chrome/browser/ui/host_desktop.h"
14 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
15 #include "chrome/common/url_constants.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/browser/web_ui.h"
18 #include "ui/base/webui/web_ui_util.h"
22 void TabToValue(const TabRestoreService::Tab& tab,
23 base::DictionaryValue* dictionary) {
24 const sessions::SerializedNavigationEntry& current_navigation =
25 tab.navigations.at(tab.current_navigation_index);
26 NewTabUI::SetUrlTitleAndDirection(dictionary, current_navigation.title(),
27 current_navigation.virtual_url());
28 dictionary->SetString("type", "tab");
29 dictionary->SetDouble("timestamp", tab.timestamp.ToDoubleT());
32 void WindowToValue(const TabRestoreService::Window& window,
33 base::DictionaryValue* dictionary) {
34 DCHECK(!window.tabs.empty());
36 scoped_ptr<base::ListValue> tab_values(new base::ListValue());
37 for (size_t i = 0; i < window.tabs.size(); ++i) {
38 base::DictionaryValue* tab_value = new base::DictionaryValue();
39 TabToValue(window.tabs[i], tab_value);
40 tab_values->Append(tab_value);
43 dictionary->SetString("type", "window");
44 dictionary->SetDouble("timestamp", window.timestamp.ToDoubleT());
45 dictionary->Set("tabs", tab_values.release());
50 void RecentlyClosedTabsHandler::RegisterMessages() {
51 web_ui()->RegisterMessageCallback("getRecentlyClosedTabs",
52 base::Bind(&RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs,
53 base::Unretained(this)));
54 web_ui()->RegisterMessageCallback("reopenTab",
55 base::Bind(&RecentlyClosedTabsHandler::HandleReopenTab,
56 base::Unretained(this)));
57 web_ui()->RegisterMessageCallback("clearRecentlyClosed",
58 base::Bind(&RecentlyClosedTabsHandler::HandleClearRecentlyClosed,
59 base::Unretained(this)));
62 RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() {
63 if (tab_restore_service_)
64 tab_restore_service_->RemoveObserver(this);
67 void RecentlyClosedTabsHandler::HandleReopenTab(const base::ListValue* args) {
68 if (!tab_restore_service_)
71 double session_to_restore = 0.0;
72 CHECK(args->GetDouble(0, &session_to_restore));
75 CHECK(args->GetDouble(1, &index));
77 // There are actually less than 20 restore tab items displayed in the UI.
78 UMA_HISTOGRAM_ENUMERATION("NewTabPage.SessionRestore",
79 static_cast<int>(index), 20);
81 TabRestoreServiceDelegate* delegate =
82 TabRestoreServiceDelegate::FindDelegateForWebContents(
83 web_ui()->GetWebContents());
86 chrome::HostDesktopType host_desktop_type =
87 chrome::GetHostDesktopTypeForNativeView(
88 web_ui()->GetWebContents()->GetNativeView());
89 WindowOpenDisposition disposition = webui::GetDispositionFromClick(args, 2);
90 tab_restore_service_->RestoreEntryById(delegate,
91 static_cast<int>(session_to_restore),
94 // The current tab has been nuked at this point; don't touch any member
98 void RecentlyClosedTabsHandler::HandleClearRecentlyClosed(
99 const base::ListValue* args) {
100 EnsureTabRestoreService();
101 if (tab_restore_service_)
102 tab_restore_service_->ClearEntries();
105 void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs(
106 const base::ListValue* args) {
107 EnsureTabRestoreService();
108 if (tab_restore_service_)
109 TabRestoreServiceChanged(tab_restore_service_);
112 void RecentlyClosedTabsHandler::TabRestoreServiceChanged(
113 TabRestoreService* service) {
114 base::ListValue list_value;
115 const int max_count = 10;
117 // We filter the list of recently closed to only show 'interesting' entries,
118 // where an interesting entry is either a closed window or a closed tab
119 // whose selected navigation is not the new tab ui.
120 for (TabRestoreService::Entries::const_iterator it =
121 service->entries().begin();
122 it != service->entries().end() && added_count < max_count; ++it) {
123 TabRestoreService::Entry* entry = *it;
124 scoped_ptr<base::DictionaryValue> entry_dict(new base::DictionaryValue());
125 if (entry->type == TabRestoreService::TAB) {
126 TabToValue(*static_cast<TabRestoreService::Tab*>(entry),
129 DCHECK_EQ(entry->type, TabRestoreService::WINDOW);
130 WindowToValue(*static_cast<TabRestoreService::Window*>(entry),
134 entry_dict->SetInteger("sessionId", entry->id);
135 list_value.Append(entry_dict.release());
139 web_ui()->CallJavascriptFunction("ntp.setRecentlyClosedTabs", list_value);
142 void RecentlyClosedTabsHandler::TabRestoreServiceDestroyed(
143 TabRestoreService* service) {
144 tab_restore_service_ = NULL;
147 void RecentlyClosedTabsHandler::EnsureTabRestoreService() {
148 if (tab_restore_service_)
151 tab_restore_service_ =
152 TabRestoreServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()));
154 // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in
155 // Off the Record mode)
156 if (tab_restore_service_) {
157 // This does nothing if the tabs have already been loaded or they
158 // shouldn't be loaded.
159 tab_restore_service_->LoadTabsFromLastSession();
160 tab_restore_service_->AddObserver(this);