• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
has_browserTab78     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