1// Copyright (c) 2012 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_HELPER_H_
6#define CHROME_BROWSER_SESSIONS_TAB_RESTORE_SERVICE_HELPER_H_
7
8#include <set>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/observer_list.h"
13#include "base/time/time.h"
14#include "chrome/browser/sessions/session_types.h"
15#include "chrome/browser/sessions/tab_restore_service.h"
16#include "chrome/browser/ui/host_desktop.h"
17#include "components/sessions/session_id.h"
18
19class Profile;
20class TabRestoreService;
21class TabRestoreServiceDelegate;
22class TabRestoreServiceObserver;
23class TimeFactory;
24
25namespace content {
26class NavigationController;
27class WebContents;
28}
29
30// Helper class used to implement InMemoryTabRestoreService and
31// PersistentTabRestoreService. See tab_restore_service.h for method-level
32// comments.
33class TabRestoreServiceHelper {
34 public:
35  typedef TabRestoreService::Entries Entries;
36  typedef TabRestoreService::Entry Entry;
37  typedef TabRestoreService::Tab Tab;
38  typedef TabRestoreService::TimeFactory TimeFactory;
39  typedef TabRestoreService::Window Window;
40
41  // Provides a way for the client to add behavior to the tab restore service
42  // helper (e.g. implementing tabs persistence).
43  class Observer {
44   public:
45    // Invoked before the entries are cleared.
46    virtual void OnClearEntries();
47
48    // Invoked before the entry is restored. |entry_iterator| points to the
49    // entry corresponding to the session identified by |id|.
50    virtual void OnRestoreEntryById(SessionID::id_type id,
51                                    Entries::const_iterator entry_iterator);
52
53    // Invoked after an entry was added.
54    virtual void OnAddEntry();
55
56   protected:
57    virtual ~Observer();
58  };
59
60  enum {
61    // Max number of entries we'll keep around.
62    kMaxEntries = 25,
63  };
64
65  // Creates a new TabRestoreServiceHelper and provides an object that provides
66  // the current time. The TabRestoreServiceHelper does not take ownership of
67  // |time_factory| and |observer|. Note that |observer| can also be NULL.
68  TabRestoreServiceHelper(TabRestoreService* tab_restore_service,
69                          Observer* observer,
70                          Profile* profile,
71                          TimeFactory* time_factory);
72
73  ~TabRestoreServiceHelper();
74
75  // Helper methods used to implement TabRestoreService.
76  void AddObserver(TabRestoreServiceObserver* observer);
77  void RemoveObserver(TabRestoreServiceObserver* observer);
78  void CreateHistoricalTab(content::WebContents* contents, int index);
79  void BrowserClosing(TabRestoreServiceDelegate* delegate);
80  void BrowserClosed(TabRestoreServiceDelegate* delegate);
81  void ClearEntries();
82  const Entries& entries() const;
83  std::vector<content::WebContents*> RestoreMostRecentEntry(
84      TabRestoreServiceDelegate* delegate,
85      chrome::HostDesktopType host_desktop_type);
86  Tab* RemoveTabEntryById(SessionID::id_type id);
87  std::vector<content::WebContents*> RestoreEntryById(
88      TabRestoreServiceDelegate* delegate,
89      SessionID::id_type id,
90      chrome::HostDesktopType host_desktop_type,
91      WindowOpenDisposition disposition);
92
93  // Notifies observers the tabs have changed.
94  void NotifyTabsChanged();
95
96  // Notifies observers the service has loaded.
97  void NotifyLoaded();
98
99  // Adds |entry| to the list of entries and takes ownership. If |prune| is true
100  // |PruneAndNotify| is invoked. If |to_front| is true the entry is added to
101  // the front, otherwise the back. Normal closes go to the front, but
102  // tab/window closes from the previous session are added to the back.
103  void AddEntry(Entry* entry, bool prune, bool to_front);
104
105  // Prunes |entries_| to contain only kMaxEntries, and removes uninteresting
106  // entries.
107  void PruneEntries();
108
109  // Returns an iterator into |entries_| whose id matches |id|. If |id|
110  // identifies a Window, then its iterator position will be returned. If it
111  // identifies a tab, then the iterator position of the Window in which the Tab
112  // resides is returned.
113  Entries::iterator GetEntryIteratorById(SessionID::id_type id);
114
115  // Calls either ValidateTab or ValidateWindow as appropriate.
116  static bool ValidateEntry(Entry* entry);
117
118 private:
119  friend class PersistentTabRestoreService;
120
121  // Populates the tab's navigations from the NavigationController, and its
122  // browser_id and pinned state from the browser.
123  void PopulateTab(Tab* tab,
124                   int index,
125                   TabRestoreServiceDelegate* delegate,
126                   content::NavigationController* controller);
127
128  // This is a helper function for RestoreEntryById() for restoring a single
129  // tab. If |delegate| is NULL, this creates a new window for the entry. This
130  // returns the TabRestoreServiceDelegate into which the tab was restored.
131  // |disposition| will be respected, but if it is UNKNOWN then the tab's
132  // original attributes will be respected instead. If a new browser needs to be
133  // created for this tab, it will be created on the desktop specified by
134  // |host_desktop_type|. If present, |contents| will be populated with the
135  // WebContents of the restored tab.
136  TabRestoreServiceDelegate* RestoreTab(
137      const Tab& tab,
138      TabRestoreServiceDelegate* delegate,
139      chrome::HostDesktopType host_desktop_type,
140      WindowOpenDisposition disposition,
141      content::WebContents** contents);
142
143  // Returns true if |tab| has more than one navigation. If |tab| has more
144  // than one navigation |tab->current_navigation_index| is constrained based
145  // on the number of navigations.
146  static bool ValidateTab(Tab* tab);
147
148  // Validates all the tabs in a window, plus the window's active tab index.
149  static bool ValidateWindow(Window* window);
150
151  // Returns true if |tab| is one we care about restoring.
152  static bool IsTabInteresting(const Tab* tab);
153
154  // Checks whether |window| is interesting --- if it only contains a single,
155  // uninteresting tab, it's not interesting.
156  static bool IsWindowInteresting(const Window* window);
157
158  // Validates and checks |entry| for interesting.
159  static bool FilterEntry(Entry* entry);
160
161  // Finds tab entries with the old browser_id and sets it to the new one.
162  void UpdateTabBrowserIDs(SessionID::id_type old_id,
163                           SessionID::id_type new_id);
164
165  // Gets the current time. This uses the time_factory_ if there is one.
166  base::Time TimeNow() const;
167
168  TabRestoreService* const tab_restore_service_;
169
170  Observer* const observer_;
171
172  Profile* const profile_;
173
174  // Set of entries. They are ordered from most to least recent.
175  Entries entries_;
176
177  // Are we restoring a tab? If this is true we ignore requests to create a
178  // historical tab.
179  bool restoring_;
180
181  ObserverList<TabRestoreServiceObserver> observer_list_;
182
183  // Set of delegates that we've received a BrowserClosing method for but no
184  // corresponding BrowserClosed. We cache the set of delegates closing to
185  // avoid creating historical tabs for them.
186  std::set<TabRestoreServiceDelegate*> closing_delegates_;
187
188  TimeFactory* const time_factory_;
189
190  DISALLOW_COPY_AND_ASSIGN(TabRestoreServiceHelper);
191};
192
193#endif  // CHROME_BROWSER_SESSIONS_TAB_RESTORE_SERVICE_HELPER_H_
194