15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/tab_restore_service_delegate.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/tab_restore_service_factory.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/new_tab_ui.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_ui.h" 184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/base/webui/web_ui_util.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabToValue(const TabRestoreService::Tab& tab, 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::DictionaryValue* dictionary) { 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const sessions::SerializedNavigationEntry& current_navigation = 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab.navigations.at(tab.current_navigation_index); 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NewTabUI::SetUrlTitleAndDirection(dictionary, current_navigation.title(), 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_navigation.virtual_url()); 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetString("type", "tab"); 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetDouble("timestamp", tab.timestamp.ToDoubleT()); 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WindowToValue(const TabRestoreService::Window& window, 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::DictionaryValue* dictionary) { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!window.tabs.empty()); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<base::ListValue> tab_values(new base::ListValue()); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < window.tabs.size(); ++i) { 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::DictionaryValue* tab_value = new base::DictionaryValue(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabToValue(window.tabs[i], tab_value); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_values->Append(tab_value); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetString("type", "window"); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->SetDouble("timestamp", window.timestamp.ToDoubleT()); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary->Set("tabs", tab_values.release()); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::RegisterMessages() { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("getRecentlyClosedTabs", 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("reopenTab", 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&RecentlyClosedTabsHandler::HandleReopenTab, 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->RegisterMessageCallback("clearRecentlyClosed", 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&RecentlyClosedTabsHandler::HandleClearRecentlyClosed, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_restore_service_) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->RemoveObserver(this); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RecentlyClosedTabsHandler::HandleReopenTab(const base::ListValue* args) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!tab_restore_service_) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double session_to_restore = 0.0; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(args->GetDouble(0, &session_to_restore)); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double index = -1.0; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(args->GetDouble(1, &index)); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There are actually less than 20 restore tab items displayed in the UI. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("NewTabPage.SessionRestore", 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(index), 20); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreServiceDelegate* delegate = 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreServiceDelegate::FindDelegateForWebContents( 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui()->GetWebContents()); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!delegate) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::HostDesktopType host_desktop_type = 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::GetHostDesktopTypeForNativeView( 88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) web_ui()->GetWebContents()->GetNativeView()); 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WindowOpenDisposition disposition = webui::GetDispositionFromClick(args, 2); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->RestoreEntryById(delegate, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(session_to_restore), 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) host_desktop_type, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disposition); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The current tab has been nuked at this point; don't touch any member 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // variables. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::HandleClearRecentlyClosed( 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::ListValue* args) { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureTabRestoreService(); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_restore_service_) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->ClearEntries(); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs( 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::ListValue* args) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureTabRestoreService(); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_restore_service_) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreServiceChanged(tab_restore_service_); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::TabRestoreServiceChanged( 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreService* service) { 1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::ListValue list_value; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int max_count = 10; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int added_count = 0; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We filter the list of recently closed to only show 'interesting' entries, 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // where an interesting entry is either a closed window or a closed tab 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whose selected navigation is not the new tab ui. 120e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch for (TabRestoreService::Entries::const_iterator it = 121e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch service->entries().begin(); 122e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch it != service->entries().end() && added_count < max_count; ++it) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreService::Entry* entry = *it; 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<base::DictionaryValue> entry_dict(new base::DictionaryValue()); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry->type == TabRestoreService::TAB) { 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabToValue(*static_cast<TabRestoreService::Tab*>(entry), 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_dict.get()); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(entry->type, TabRestoreService::WINDOW); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WindowToValue(*static_cast<TabRestoreService::Window*>(entry), 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_dict.get()); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_dict->SetInteger("sessionId", entry->id); 135e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch list_value.Append(entry_dict.release()); 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++added_count; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 138e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 139e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch web_ui()->CallJavascriptFunction("ntp.setRecentlyClosedTabs", list_value); 140e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch} 141e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 142e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid RecentlyClosedTabsHandler::TabRestoreServiceDestroyed( 143e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch TabRestoreService* service) { 144e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch tab_restore_service_ = NULL; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecentlyClosedTabsHandler::EnsureTabRestoreService() { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_restore_service_) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_ = 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabRestoreServiceFactory::GetForProfile(Profile::FromWebUI(web_ui())); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Off the Record mode) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_restore_service_) { 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This does nothing if the tabs have already been loaded or they 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // shouldn't be loaded. 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->LoadTabsFromLastSession(); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_restore_service_->AddObserver(this); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 163