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_ui.h"
     18 #include "ui/base/webui/web_ui_util.h"
     19 
     20 namespace {
     21 
     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());
     30 }
     31 
     32 void WindowToValue(const TabRestoreService::Window& window,
     33                    base::DictionaryValue* dictionary) {
     34   DCHECK(!window.tabs.empty());
     35 
     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);
     41   }
     42 
     43   dictionary->SetString("type", "window");
     44   dictionary->SetDouble("timestamp", window.timestamp.ToDoubleT());
     45   dictionary->Set("tabs", tab_values.release());
     46 }
     47 
     48 }  // namespace
     49 
     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)));
     60 }
     61 
     62 RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() {
     63   if (tab_restore_service_)
     64     tab_restore_service_->RemoveObserver(this);
     65 }
     66 
     67 void RecentlyClosedTabsHandler::HandleReopenTab(const base::ListValue* args) {
     68   if (!tab_restore_service_)
     69     return;
     70 
     71   double session_to_restore = 0.0;
     72   CHECK(args->GetDouble(0, &session_to_restore));
     73 
     74   double index = -1.0;
     75   CHECK(args->GetDouble(1, &index));
     76 
     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);
     80 
     81   TabRestoreServiceDelegate* delegate =
     82       TabRestoreServiceDelegate::FindDelegateForWebContents(
     83           web_ui()->GetWebContents());
     84   if (!delegate)
     85     return;
     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),
     92                                          host_desktop_type,
     93                                          disposition);
     94   // The current tab has been nuked at this point; don't touch any member
     95   // variables.
     96 }
     97 
     98 void RecentlyClosedTabsHandler::HandleClearRecentlyClosed(
     99     const base::ListValue* args) {
    100   EnsureTabRestoreService();
    101   if (tab_restore_service_)
    102     tab_restore_service_->ClearEntries();
    103 }
    104 
    105 void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs(
    106     const base::ListValue* args) {
    107   EnsureTabRestoreService();
    108   if (tab_restore_service_)
    109     TabRestoreServiceChanged(tab_restore_service_);
    110 }
    111 
    112 void RecentlyClosedTabsHandler::TabRestoreServiceChanged(
    113     TabRestoreService* service) {
    114   base::ListValue list_value;
    115   const int max_count = 10;
    116   int added_count = 0;
    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),
    127                  entry_dict.get());
    128     } else  {
    129       DCHECK_EQ(entry->type, TabRestoreService::WINDOW);
    130       WindowToValue(*static_cast<TabRestoreService::Window*>(entry),
    131                     entry_dict.get());
    132     }
    133 
    134     entry_dict->SetInteger("sessionId", entry->id);
    135     list_value.Append(entry_dict.release());
    136     ++added_count;
    137   }
    138 
    139   web_ui()->CallJavascriptFunction("ntp.setRecentlyClosedTabs", list_value);
    140 }
    141 
    142 void RecentlyClosedTabsHandler::TabRestoreServiceDestroyed(
    143     TabRestoreService* service) {
    144   tab_restore_service_ = NULL;
    145 }
    146 
    147 void RecentlyClosedTabsHandler::EnsureTabRestoreService() {
    148   if (tab_restore_service_)
    149     return;
    150 
    151   tab_restore_service_ =
    152       TabRestoreServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()));
    153 
    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);
    161   }
    162 }
    163