C++程序  |  345行  |  12.19 KB

// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_SESSIONS_TAB_RESTORE_SERVICE_H_
#define CHROME_BROWSER_SESSIONS_TAB_RESTORE_SERVICE_H_
#pragma once

#include <list>
#include <set>
#include <vector>

#include "base/observer_list.h"
#include "base/time.h"
#include "chrome/browser/sessions/base_session_service.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/browser/sessions/session_types.h"
#include "content/browser/in_process_webkit/session_storage_namespace.h"

class NavigationController;
class Profile;
class TabRestoreServiceDelegate;
class TabRestoreServiceObserver;
struct SessionWindow;

// TabRestoreService is responsible for maintaining the most recently closed
// tabs and windows. When a tab is closed
// TabRestoreService::CreateHistoricalTab is invoked and a Tab is created to
// represent the tab. Similarly, when a browser is closed, BrowserClosing is
// invoked and a Window is created to represent the window.
//
// To restore a tab/window from the TabRestoreService invoke RestoreEntryById
// or RestoreMostRecentEntry.
//
// To listen for changes to the set of entries managed by the TabRestoreService
// add an observer.
class TabRestoreService : public BaseSessionService {
 public:
  // Interface used to allow the test to provide a custom time.
  class TimeFactory {
   public:
    virtual ~TimeFactory();
    virtual base::Time TimeNow() = 0;
  };

  // The type of entry.
  enum Type {
    TAB,
    WINDOW
  };

  struct Entry {
    Entry();
    explicit Entry(Type type);
    virtual ~Entry();

    // Unique id for this entry. The id is guaranteed to be unique for a
    // session.
    SessionID::id_type id;

    // The type of the entry.
    Type type;

    // The time when the window or tab was closed.
    base::Time timestamp;

    // Is this entry from the last session? This is set to true for entries that
    // were closed during the last session, and false for entries that were
    // closed during this session.
    bool from_last_session;
  };

  // Represents a previously open tab.
  struct Tab : public Entry {
    Tab();
    virtual ~Tab();

    bool has_browser() const { return browser_id > 0; }

    // The navigations.
    std::vector<TabNavigation> navigations;

    // Index of the selected navigation in navigations.
    int current_navigation_index;

    // The ID of the browser to which this tab belonged, so it can be restored
    // there. May be 0 (an invalid SessionID) when restoring an entire session.
    SessionID::id_type browser_id;

    // Index within the tab strip. May be -1 for an unknown index.
    int tabstrip_index;

    // True if the tab was pinned.
    bool pinned;

    // If non-empty gives the id of the extension for the tab.
    std::string extension_app_id;

    // The associated session storage namespace (if any).
    scoped_refptr<SessionStorageNamespace> session_storage_namespace;
  };

  // Represents a previously open window.
  struct Window : public Entry {
    Window();
    virtual ~Window();

    // The tabs that comprised the window, in order.
    std::vector<Tab> tabs;

    // Index of the selected tab.
    int selected_tab_index;
  };

  typedef std::list<Entry*> Entries;

  // Creates a new TabRestoreService and provides an object that provides the
  // current time. The TabRestoreService does not take ownership of the
  // |time_factory_|.
  explicit TabRestoreService(Profile* profile,
                             TimeFactory* time_factory_ = NULL);

  // Adds/removes an observer. TabRestoreService does not take ownership of
  // the observer.
  void AddObserver(TabRestoreServiceObserver* observer);
  void RemoveObserver(TabRestoreServiceObserver* observer);

  // Creates a Tab to represent |tab| and notifies observers the list of
  // entries has changed.
  void CreateHistoricalTab(NavigationController* tab, int index);

  // Invoked when a browser is closing. If |delegate| is a tabbed browser with
  // at least one tab, a Window is created, added to entries and observers are
  // notified.
  void BrowserClosing(TabRestoreServiceDelegate* delegate);

  // Invoked when the browser is done closing.
  void BrowserClosed(TabRestoreServiceDelegate* delegate);

  // Removes all entries from the list and notifies observers the list
  // of tabs has changed.
  void ClearEntries();

  // Returns the entries, ordered with most recently closed entries at the
  // front.
  virtual const Entries& entries() const;

  // Restores the most recently closed entry. Does nothing if there are no
  // entries to restore. If the most recently restored entry is a tab, it is
  // added to |delegate|.
  void RestoreMostRecentEntry(TabRestoreServiceDelegate* delegate);

  // Restores an entry by id. If there is no entry with an id matching |id|,
  // this does nothing. If |replace_existing_tab| is true and id identifies a
  // tab, the newly created tab replaces the selected tab in |delegate|. If
  // |delegate| is NULL, this creates a new window for the entry.
  void RestoreEntryById(TabRestoreServiceDelegate* delegate,
                        SessionID::id_type id,
                        bool replace_existing_tab);

  // Loads the tabs and previous session. This does nothing if the tabs
  // from the previous session have already been loaded.
  void LoadTabsFromLastSession();

  // Max number of entries we'll keep around.
  static const size_t kMaxEntries;

  // Creates and add entries to |entries| for each of the windows in |windows|.
  void CreateEntriesFromWindows(std::vector<SessionWindow*>* windows,
                                std::vector<Entry*>* entries);

 protected:
  virtual void Save();

  virtual ~TabRestoreService();

 private:
  // Used to indicate what has loaded.
  enum LoadState {
    // Indicates we haven't loaded anything.
    NOT_LOADED           = 1 << 0,

    // Indicates we've asked for the last sessions and tabs but haven't gotten
    // the result back yet.
    LOADING              = 1 << 2,

    // Indicates we finished loading the last tabs (but not necessarily the
    // last session).
    LOADED_LAST_TABS     = 1 << 3,

    // Indicates we finished loading the last session (but not necessarily the
    // last tabs).
    LOADED_LAST_SESSION  = 1 << 4
  };

  // Populates the tab's navigations from the NavigationController, and its
  // browser_id and pinned state from the browser.
  void PopulateTab(Tab* tab,
                   int index,
                   TabRestoreServiceDelegate* delegate,
                   NavigationController* controller);

  // Notifies observers the tabs have changed.
  void NotifyTabsChanged();

  // Adds |entry| to the list of entries and takes ownership. If |prune| is true
  // |PruneAndNotify| is invoked. If |to_front| is true the entry is added to
  // the front, otherwise the back. Normal closes go to the front, but
  // tab/window closes from the previous session are added to the back.
  void AddEntry(Entry* entry, bool prune, bool to_front);

  // Prunes entries_ to contain only kMaxEntries and invokes NotifyTabsChanged.
  void PruneAndNotify();

  // Returns an iterator into entries_ whose id matches |id|. If |id| identifies
  // a Window, then its iterator position will be returned. If it identifies a
  // tab, then the iterator position of the Window in which the Tab resides is
  // returned.
  Entries::iterator GetEntryIteratorById(SessionID::id_type id);

  // Schedules the commands for a window close.
  void ScheduleCommandsForWindow(const Window& window);

  // Schedules the commands for a tab close. |selected_index| gives the
  // index of the selected navigation.
  void ScheduleCommandsForTab(const Tab& tab, int selected_index);

  // Creates a window close command.
  SessionCommand* CreateWindowCommand(SessionID::id_type id,
                                      int selected_tab_index,
                                      int num_tabs,
                                      base::Time timestamp);

  // Creates a tab close command.
  SessionCommand* CreateSelectedNavigationInTabCommand(
      SessionID::id_type tab_id,
      int32 index,
      base::Time timestamp);

  // Creates a restore command.
  SessionCommand* CreateRestoredEntryCommand(SessionID::id_type entry_id);

  // Returns the index to persist as the selected index. This is the same
  // as |tab.current_navigation_index| unless the entry at
  // |tab.current_navigation_index| shouldn't be persisted. Returns -1 if
  // no valid navigation to persist.
  int GetSelectedNavigationIndexToPersist(const Tab& tab);

  // Invoked when we've loaded the session commands that identify the
  // previously closed tabs. This creates entries, adds them to
  // staging_entries_, and invokes LoadState.
  void OnGotLastSessionCommands(
      Handle handle,
      scoped_refptr<InternalGetCommandsRequest> request);

  // Populates |loaded_entries| with Entries from |request|.
  void CreateEntriesFromCommands(
      scoped_refptr<InternalGetCommandsRequest> request,
      std::vector<Entry*>* loaded_entries);

  // This is a helper function for RestoreEntryById() for restoring a single
  // tab. If |replace_existing_tab| is true, the newly created tab replaces the
  // selected tab in |delegate|. If |delegate| is NULL, this creates a new
  // window for the entry. This returns the TabRestoreServiceDelegate into which
  // the tab was restored.
  TabRestoreServiceDelegate* RestoreTab(const Tab& tab,
                                        TabRestoreServiceDelegate* delegate,
                                        bool replace_existing_tab);

  // Returns true if |tab| has more than one navigation. If |tab| has more
  // than one navigation |tab->current_navigation_index| is constrained based
  // on the number of navigations.
  bool ValidateTab(Tab* tab);

  // Validates all entries in |entries|, deleting any with no navigations.
  // This also deletes any entries beyond the max number of entries we can
  // hold.
  void ValidateAndDeleteEmptyEntries(std::vector<Entry*>* entries);

  // Finds tab entries with the old browser_id and sets it to the new one.
  void UpdateTabBrowserIDs(SessionID::id_type old_id,
                           SessionID::id_type new_id);

  // Callback from SessionService when we've received the windows from the
  // previous session. This creates and add entries to |staging_entries_|
  // and invokes LoadStateChanged.
  void OnGotPreviousSession(Handle handle,
                            std::vector<SessionWindow*>* windows);

  // Converts a SessionWindow into a Window, returning true on success. We use 0
  // as the timestamp here since we do not know when the window/tab was closed.
  bool ConvertSessionWindowToWindow(
      SessionWindow* session_window,
      Window* window);

  // Invoked when previous tabs or session is loaded. If both have finished
  // loading the entries in staging_entries_ are added to entries_ and
  // observers are notified.
  void LoadStateChanged();

  // Gets the current time. This uses the time_factory_ if there is one.
  base::Time TimeNow() const;

  // Set of entries.
  Entries entries_;

  // Whether we've loaded the last session.
  int load_state_;

  // Are we restoring a tab? If this is true we ignore requests to create a
  // historical tab.
  bool restoring_;

  // Have the max number of entries ever been created?
  bool reached_max_;

  // The number of entries to write.
  int entries_to_write_;

  // Number of entries we've written.
  int entries_written_;

  ObserverList<TabRestoreServiceObserver> observer_list_;

  // Set of delegates that we've received a BrowserClosing method for but no
  // corresponding BrowserClosed. We cache the set of delegates closing to
  // avoid creating historical tabs for them.
  std::set<TabRestoreServiceDelegate*> closing_delegates_;

  // Used when loading previous tabs/session.
  CancelableRequestConsumer load_consumer_;

  // Results from previously closed tabs/sessions is first added here. When
  // the results from both us and the session restore service have finished
  // loading LoadStateChanged is invoked, which adds these entries to
  // entries_.
  std::vector<Entry*> staging_entries_;

  TimeFactory* time_factory_;

  DISALLOW_COPY_AND_ASSIGN(TabRestoreService);
};

#endif  // CHROME_BROWSER_SESSIONS_TAB_RESTORE_SERVICE_H_