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