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. 4 5 #include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h" 6 7 #include "base/bind.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_contents_view.h" 18 #include "content/public/browser/web_ui.h" 19 #include "ui/webui/web_ui_util.h" 20 21 #if defined(OS_ANDROID) 22 #include "chrome/browser/sessions/session_restore.h" 23 #endif 24 25 namespace { 26 27 void TabToValue(const TabRestoreService::Tab& tab, 28 DictionaryValue* dictionary) { 29 const sessions::SerializedNavigationEntry& current_navigation = 30 tab.navigations.at(tab.current_navigation_index); 31 NewTabUI::SetUrlTitleAndDirection(dictionary, current_navigation.title(), 32 current_navigation.virtual_url()); 33 dictionary->SetString("type", "tab"); 34 dictionary->SetDouble("timestamp", tab.timestamp.ToDoubleT()); 35 } 36 37 void WindowToValue(const TabRestoreService::Window& window, 38 DictionaryValue* dictionary) { 39 DCHECK(!window.tabs.empty()); 40 41 scoped_ptr<ListValue> tab_values(new ListValue()); 42 for (size_t i = 0; i < window.tabs.size(); ++i) { 43 DictionaryValue* tab_value = new DictionaryValue(); 44 TabToValue(window.tabs[i], tab_value); 45 tab_values->Append(tab_value); 46 } 47 48 dictionary->SetString("type", "window"); 49 dictionary->SetDouble("timestamp", window.timestamp.ToDoubleT()); 50 dictionary->Set("tabs", tab_values.release()); 51 } 52 53 } // namespace 54 55 void RecentlyClosedTabsHandler::RegisterMessages() { 56 web_ui()->RegisterMessageCallback("getRecentlyClosedTabs", 57 base::Bind(&RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs, 58 base::Unretained(this))); 59 web_ui()->RegisterMessageCallback("reopenTab", 60 base::Bind(&RecentlyClosedTabsHandler::HandleReopenTab, 61 base::Unretained(this))); 62 web_ui()->RegisterMessageCallback("clearRecentlyClosed", 63 base::Bind(&RecentlyClosedTabsHandler::HandleClearRecentlyClosed, 64 base::Unretained(this))); 65 } 66 67 RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() { 68 if (tab_restore_service_) 69 tab_restore_service_->RemoveObserver(this); 70 } 71 72 void RecentlyClosedTabsHandler::HandleReopenTab(const ListValue* args) { 73 if (!tab_restore_service_) 74 return; 75 76 double session_to_restore = 0.0; 77 CHECK(args->GetDouble(0, &session_to_restore)); 78 79 #if defined(OS_ANDROID) 80 // Find and remove the corresponding tab entry from TabRestoreService. 81 // We take ownership of the returned tab. 82 scoped_ptr<TabRestoreService::Tab> tab_entry( 83 tab_restore_service_->RemoveTabEntryById(static_cast<int>( 84 session_to_restore))); 85 if (tab_entry.get() == NULL) 86 return; 87 88 // RestoreForeignSessionTab needs a SessionTab. 89 SessionTab session_tab; 90 session_tab.current_navigation_index = tab_entry->current_navigation_index; 91 session_tab.navigations = tab_entry->navigations; 92 93 SessionRestore::RestoreForeignSessionTab(web_ui()->GetWebContents(), 94 session_tab, NEW_FOREGROUND_TAB); 95 #else 96 double index = -1.0; 97 CHECK(args->GetDouble(1, &index)); 98 99 // There are actually less than 20 restore tab items displayed in the UI. 100 UMA_HISTOGRAM_ENUMERATION("NewTabPage.SessionRestore", 101 static_cast<int>(index), 20); 102 103 TabRestoreServiceDelegate* delegate = 104 TabRestoreServiceDelegate::FindDelegateForWebContents( 105 web_ui()->GetWebContents()); 106 if (!delegate) 107 return; 108 chrome::HostDesktopType host_desktop_type = 109 chrome::GetHostDesktopTypeForNativeView( 110 web_ui()->GetWebContents()->GetView()->GetNativeView()); 111 WindowOpenDisposition disposition = webui::GetDispositionFromClick(args, 2); 112 tab_restore_service_->RestoreEntryById(delegate, 113 static_cast<int>(session_to_restore), 114 host_desktop_type, 115 disposition); 116 // The current tab has been nuked at this point; don't touch any member 117 // variables. 118 #endif 119 } 120 121 void RecentlyClosedTabsHandler::HandleClearRecentlyClosed( 122 const ListValue* args) { 123 EnsureTabRestoreService(); 124 if (tab_restore_service_) 125 tab_restore_service_->ClearEntries(); 126 } 127 128 void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs( 129 const ListValue* args) { 130 EnsureTabRestoreService(); 131 if (tab_restore_service_) 132 TabRestoreServiceChanged(tab_restore_service_); 133 } 134 135 void RecentlyClosedTabsHandler::TabRestoreServiceChanged( 136 TabRestoreService* service) { 137 ListValue list_value; 138 TabRestoreService::Entries entries = service->entries(); 139 CreateRecentlyClosedValues(entries, &list_value); 140 141 web_ui()->CallJavascriptFunction("ntp.setRecentlyClosedTabs", list_value); 142 } 143 144 void RecentlyClosedTabsHandler::TabRestoreServiceDestroyed( 145 TabRestoreService* service) { 146 tab_restore_service_ = NULL; 147 } 148 149 // static 150 void RecentlyClosedTabsHandler::CreateRecentlyClosedValues( 151 const TabRestoreService::Entries& entries, ListValue* entry_list_value) { 152 const int max_count = 10; 153 int added_count = 0; 154 // We filter the list of recently closed to only show 'interesting' entries, 155 // where an interesting entry is either a closed window or a closed tab 156 // whose selected navigation is not the new tab ui. 157 for (TabRestoreService::Entries::const_iterator it = entries.begin(); 158 it != entries.end() && added_count < max_count; ++it) { 159 TabRestoreService::Entry* entry = *it; 160 scoped_ptr<DictionaryValue> entry_dict(new DictionaryValue()); 161 if (entry->type == TabRestoreService::TAB) { 162 TabToValue(*static_cast<TabRestoreService::Tab*>(entry), 163 entry_dict.get()); 164 } else { 165 DCHECK_EQ(entry->type, TabRestoreService::WINDOW); 166 WindowToValue(*static_cast<TabRestoreService::Window*>(entry), 167 entry_dict.get()); 168 } 169 170 entry_dict->SetInteger("sessionId", entry->id); 171 entry_list_value->Append(entry_dict.release()); 172 ++added_count; 173 } 174 } 175 176 void RecentlyClosedTabsHandler::EnsureTabRestoreService() { 177 if (tab_restore_service_) 178 return; 179 180 tab_restore_service_ = 181 TabRestoreServiceFactory::GetForProfile(Profile::FromWebUI(web_ui())); 182 183 // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in 184 // Off the Record mode) 185 if (tab_restore_service_) { 186 // This does nothing if the tabs have already been loaded or they 187 // shouldn't be loaded. 188 tab_restore_service_->LoadTabsFromLastSession(); 189 tab_restore_service_->AddObserver(this); 190 } 191 } 192