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