Home | History | Annotate | Download | only in ntp
      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