Home | History | Annotate | Download | only in sessions
      1 // Copyright (c) 2010 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 #ifndef CHROME_BROWSER_SESSIONS_TAB_RESTORE_SERVICE_H_
      6 #define CHROME_BROWSER_SESSIONS_TAB_RESTORE_SERVICE_H_
      7 #pragma once
      8 
      9 #include <list>
     10 #include <set>
     11 #include <vector>
     12 
     13 #include "base/observer_list.h"
     14 #include "base/time.h"
     15 #include "chrome/browser/sessions/base_session_service.h"
     16 #include "chrome/browser/sessions/session_id.h"
     17 #include "chrome/browser/sessions/session_types.h"
     18 #include "content/browser/in_process_webkit/session_storage_namespace.h"
     19 
     20 class NavigationController;
     21 class Profile;
     22 class TabRestoreServiceDelegate;
     23 class TabRestoreServiceObserver;
     24 struct SessionWindow;
     25 
     26 // TabRestoreService is responsible for maintaining the most recently closed
     27 // tabs and windows. When a tab is closed
     28 // TabRestoreService::CreateHistoricalTab is invoked and a Tab is created to
     29 // represent the tab. Similarly, when a browser is closed, BrowserClosing is
     30 // invoked and a Window is created to represent the window.
     31 //
     32 // To restore a tab/window from the TabRestoreService invoke RestoreEntryById
     33 // or RestoreMostRecentEntry.
     34 //
     35 // To listen for changes to the set of entries managed by the TabRestoreService
     36 // add an observer.
     37 class TabRestoreService : public BaseSessionService {
     38  public:
     39   // Interface used to allow the test to provide a custom time.
     40   class TimeFactory {
     41    public:
     42     virtual ~TimeFactory();
     43     virtual base::Time TimeNow() = 0;
     44   };
     45 
     46   // The type of entry.
     47   enum Type {
     48     TAB,
     49     WINDOW
     50   };
     51 
     52   struct Entry {
     53     Entry();
     54     explicit Entry(Type type);
     55     virtual ~Entry();
     56 
     57     // Unique id for this entry. The id is guaranteed to be unique for a
     58     // session.
     59     SessionID::id_type id;
     60 
     61     // The type of the entry.
     62     Type type;
     63 
     64     // The time when the window or tab was closed.
     65     base::Time timestamp;
     66 
     67     // Is this entry from the last session? This is set to true for entries that
     68     // were closed during the last session, and false for entries that were
     69     // closed during this session.
     70     bool from_last_session;
     71   };
     72 
     73   // Represents a previously open tab.
     74   struct Tab : public Entry {
     75     Tab();
     76     virtual ~Tab();
     77 
     78     bool has_browser() const { return browser_id > 0; }
     79 
     80     // The navigations.
     81     std::vector<TabNavigation> navigations;
     82 
     83     // Index of the selected navigation in navigations.
     84     int current_navigation_index;
     85 
     86     // The ID of the browser to which this tab belonged, so it can be restored
     87     // there. May be 0 (an invalid SessionID) when restoring an entire session.
     88     SessionID::id_type browser_id;
     89 
     90     // Index within the tab strip. May be -1 for an unknown index.
     91     int tabstrip_index;
     92 
     93     // True if the tab was pinned.
     94     bool pinned;
     95 
     96     // If non-empty gives the id of the extension for the tab.
     97     std::string extension_app_id;
     98 
     99     // The associated session storage namespace (if any).
    100     scoped_refptr<SessionStorageNamespace> session_storage_namespace;
    101   };
    102 
    103   // Represents a previously open window.
    104   struct Window : public Entry {
    105     Window();
    106     virtual ~Window();
    107 
    108     // The tabs that comprised the window, in order.
    109     std::vector<Tab> tabs;
    110 
    111     // Index of the selected tab.
    112     int selected_tab_index;
    113   };
    114 
    115   typedef std::list<Entry*> Entries;
    116 
    117   // Creates a new TabRestoreService and provides an object that provides the
    118   // current time. The TabRestoreService does not take ownership of the
    119   // |time_factory_|.
    120   explicit TabRestoreService(Profile* profile,
    121                              TimeFactory* time_factory_ = NULL);
    122 
    123   // Adds/removes an observer. TabRestoreService does not take ownership of
    124   // the observer.
    125   void AddObserver(TabRestoreServiceObserver* observer);
    126   void RemoveObserver(TabRestoreServiceObserver* observer);
    127 
    128   // Creates a Tab to represent |tab| and notifies observers the list of
    129   // entries has changed.
    130   void CreateHistoricalTab(NavigationController* tab, int index);
    131 
    132   // Invoked when a browser is closing. If |delegate| is a tabbed browser with
    133   // at least one tab, a Window is created, added to entries and observers are
    134   // notified.
    135   void BrowserClosing(TabRestoreServiceDelegate* delegate);
    136 
    137   // Invoked when the browser is done closing.
    138   void BrowserClosed(TabRestoreServiceDelegate* delegate);
    139 
    140   // Removes all entries from the list and notifies observers the list
    141   // of tabs has changed.
    142   void ClearEntries();
    143 
    144   // Returns the entries, ordered with most recently closed entries at the
    145   // front.
    146   virtual const Entries& entries() const;
    147 
    148   // Restores the most recently closed entry. Does nothing if there are no
    149   // entries to restore. If the most recently restored entry is a tab, it is
    150   // added to |delegate|.
    151   void RestoreMostRecentEntry(TabRestoreServiceDelegate* delegate);
    152 
    153   // Restores an entry by id. If there is no entry with an id matching |id|,
    154   // this does nothing. If |replace_existing_tab| is true and id identifies a
    155   // tab, the newly created tab replaces the selected tab in |delegate|. If
    156   // |delegate| is NULL, this creates a new window for the entry.
    157   void RestoreEntryById(TabRestoreServiceDelegate* delegate,
    158                         SessionID::id_type id,
    159                         bool replace_existing_tab);
    160 
    161   // Loads the tabs and previous session. This does nothing if the tabs
    162   // from the previous session have already been loaded.
    163   void LoadTabsFromLastSession();
    164 
    165   // Max number of entries we'll keep around.
    166   static const size_t kMaxEntries;
    167 
    168   // Creates and add entries to |entries| for each of the windows in |windows|.
    169   void CreateEntriesFromWindows(std::vector<SessionWindow*>* windows,
    170                                 std::vector<Entry*>* entries);
    171 
    172  protected:
    173   virtual void Save();
    174 
    175   virtual ~TabRestoreService();
    176 
    177  private:
    178   // Used to indicate what has loaded.
    179   enum LoadState {
    180     // Indicates we haven't loaded anything.
    181     NOT_LOADED           = 1 << 0,
    182 
    183     // Indicates we've asked for the last sessions and tabs but haven't gotten
    184     // the result back yet.
    185     LOADING              = 1 << 2,
    186 
    187     // Indicates we finished loading the last tabs (but not necessarily the
    188     // last session).
    189     LOADED_LAST_TABS     = 1 << 3,
    190 
    191     // Indicates we finished loading the last session (but not necessarily the
    192     // last tabs).
    193     LOADED_LAST_SESSION  = 1 << 4
    194   };
    195 
    196   // Populates the tab's navigations from the NavigationController, and its
    197   // browser_id and pinned state from the browser.
    198   void PopulateTab(Tab* tab,
    199                    int index,
    200                    TabRestoreServiceDelegate* delegate,
    201                    NavigationController* controller);
    202 
    203   // Notifies observers the tabs have changed.
    204   void NotifyTabsChanged();
    205 
    206   // Adds |entry| to the list of entries and takes ownership. If |prune| is true
    207   // |PruneAndNotify| is invoked. If |to_front| is true the entry is added to
    208   // the front, otherwise the back. Normal closes go to the front, but
    209   // tab/window closes from the previous session are added to the back.
    210   void AddEntry(Entry* entry, bool prune, bool to_front);
    211 
    212   // Prunes entries_ to contain only kMaxEntries and invokes NotifyTabsChanged.
    213   void PruneAndNotify();
    214 
    215   // Returns an iterator into entries_ whose id matches |id|. If |id| identifies
    216   // a Window, then its iterator position will be returned. If it identifies a
    217   // tab, then the iterator position of the Window in which the Tab resides is
    218   // returned.
    219   Entries::iterator GetEntryIteratorById(SessionID::id_type id);
    220 
    221   // Schedules the commands for a window close.
    222   void ScheduleCommandsForWindow(const Window& window);
    223 
    224   // Schedules the commands for a tab close. |selected_index| gives the
    225   // index of the selected navigation.
    226   void ScheduleCommandsForTab(const Tab& tab, int selected_index);
    227 
    228   // Creates a window close command.
    229   SessionCommand* CreateWindowCommand(SessionID::id_type id,
    230                                       int selected_tab_index,
    231                                       int num_tabs,
    232                                       base::Time timestamp);
    233 
    234   // Creates a tab close command.
    235   SessionCommand* CreateSelectedNavigationInTabCommand(
    236       SessionID::id_type tab_id,
    237       int32 index,
    238       base::Time timestamp);
    239 
    240   // Creates a restore command.
    241   SessionCommand* CreateRestoredEntryCommand(SessionID::id_type entry_id);
    242 
    243   // Returns the index to persist as the selected index. This is the same
    244   // as |tab.current_navigation_index| unless the entry at
    245   // |tab.current_navigation_index| shouldn't be persisted. Returns -1 if
    246   // no valid navigation to persist.
    247   int GetSelectedNavigationIndexToPersist(const Tab& tab);
    248 
    249   // Invoked when we've loaded the session commands that identify the
    250   // previously closed tabs. This creates entries, adds them to
    251   // staging_entries_, and invokes LoadState.
    252   void OnGotLastSessionCommands(
    253       Handle handle,
    254       scoped_refptr<InternalGetCommandsRequest> request);
    255 
    256   // Populates |loaded_entries| with Entries from |request|.
    257   void CreateEntriesFromCommands(
    258       scoped_refptr<InternalGetCommandsRequest> request,
    259       std::vector<Entry*>* loaded_entries);
    260 
    261   // This is a helper function for RestoreEntryById() for restoring a single
    262   // tab. If |replace_existing_tab| is true, the newly created tab replaces the
    263   // selected tab in |delegate|. If |delegate| is NULL, this creates a new
    264   // window for the entry. This returns the TabRestoreServiceDelegate into which
    265   // the tab was restored.
    266   TabRestoreServiceDelegate* RestoreTab(const Tab& tab,
    267                                         TabRestoreServiceDelegate* delegate,
    268                                         bool replace_existing_tab);
    269 
    270   // Returns true if |tab| has more than one navigation. If |tab| has more
    271   // than one navigation |tab->current_navigation_index| is constrained based
    272   // on the number of navigations.
    273   bool ValidateTab(Tab* tab);
    274 
    275   // Validates all entries in |entries|, deleting any with no navigations.
    276   // This also deletes any entries beyond the max number of entries we can
    277   // hold.
    278   void ValidateAndDeleteEmptyEntries(std::vector<Entry*>* entries);
    279 
    280   // Finds tab entries with the old browser_id and sets it to the new one.
    281   void UpdateTabBrowserIDs(SessionID::id_type old_id,
    282                            SessionID::id_type new_id);
    283 
    284   // Callback from SessionService when we've received the windows from the
    285   // previous session. This creates and add entries to |staging_entries_|
    286   // and invokes LoadStateChanged.
    287   void OnGotPreviousSession(Handle handle,
    288                             std::vector<SessionWindow*>* windows);
    289 
    290   // Converts a SessionWindow into a Window, returning true on success. We use 0
    291   // as the timestamp here since we do not know when the window/tab was closed.
    292   bool ConvertSessionWindowToWindow(
    293       SessionWindow* session_window,
    294       Window* window);
    295 
    296   // Invoked when previous tabs or session is loaded. If both have finished
    297   // loading the entries in staging_entries_ are added to entries_ and
    298   // observers are notified.
    299   void LoadStateChanged();
    300 
    301   // Gets the current time. This uses the time_factory_ if there is one.
    302   base::Time TimeNow() const;
    303 
    304   // Set of entries.
    305   Entries entries_;
    306 
    307   // Whether we've loaded the last session.
    308   int load_state_;
    309 
    310   // Are we restoring a tab? If this is true we ignore requests to create a
    311   // historical tab.
    312   bool restoring_;
    313 
    314   // Have the max number of entries ever been created?
    315   bool reached_max_;
    316 
    317   // The number of entries to write.
    318   int entries_to_write_;
    319 
    320   // Number of entries we've written.
    321   int entries_written_;
    322 
    323   ObserverList<TabRestoreServiceObserver> observer_list_;
    324 
    325   // Set of delegates that we've received a BrowserClosing method for but no
    326   // corresponding BrowserClosed. We cache the set of delegates closing to
    327   // avoid creating historical tabs for them.
    328   std::set<TabRestoreServiceDelegate*> closing_delegates_;
    329 
    330   // Used when loading previous tabs/session.
    331   CancelableRequestConsumer load_consumer_;
    332 
    333   // Results from previously closed tabs/sessions is first added here. When
    334   // the results from both us and the session restore service have finished
    335   // loading LoadStateChanged is invoked, which adds these entries to
    336   // entries_.
    337   std::vector<Entry*> staging_entries_;
    338 
    339   TimeFactory* time_factory_;
    340 
    341   DISALLOW_COPY_AND_ASSIGN(TabRestoreService);
    342 };
    343 
    344 #endif  // CHROME_BROWSER_SESSIONS_TAB_RESTORE_SERVICE_H_
    345