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.
5 #include "base/logging.h"
6 #include "base/stl_util.h"
7 #include "base/utf_string_conversions.h"
8 #include "chrome/browser/sync/glue/synced_session_tracker.h"
10 namespace browser_sync
{
12 SyncedSessionTracker::SyncedSessionTracker() {
15 SyncedSessionTracker::~SyncedSessionTracker() {
19 void SyncedSessionTracker::SetLocalSessionTag(
20 const std::string
& local_session_tag
) {
21 local_session_tag_
= local_session_tag
;
24 bool SyncedSessionTracker::LookupAllForeignSessions(
25 std::vector
<const SyncedSession
*>* sessions
) const {
28 // Fill vector of sessions from our synced session map.
29 for (SyncedSessionMap::const_iterator i
=
30 synced_session_map_
.begin(); i
!= synced_session_map_
.end(); ++i
) {
31 // Only include foreign sessions with open tabs.
32 SyncedSession
* foreign_session
= i
->second
;
33 if (i
->first
!= local_session_tag_
&& !foreign_session
->windows
.empty()) {
34 bool found_tabs
= false;
35 for (SyncedSession::SyncedWindowMap::const_iterator iter
=
36 foreign_session
->windows
.begin();
37 iter
!= foreign_session
->windows
.end(); ++iter
) {
38 if (!SessionWindowHasNoTabsToSync(*(iter
->second
))) {
44 sessions
->push_back(foreign_session
);
48 return !sessions
->empty();
51 bool SyncedSessionTracker::LookupSessionWindows(
52 const std::string
& session_tag
,
53 std::vector
<const SessionWindow
*>* windows
) const {
56 SyncedSessionMap::const_iterator iter
= synced_session_map_
.find(session_tag
);
57 if (iter
== synced_session_map_
.end())
60 for (SyncedSession::SyncedWindowMap::const_iterator window_iter
=
61 iter
->second
->windows
.begin();
62 window_iter
!= iter
->second
->windows
.end(); window_iter
++) {
63 windows
->push_back(window_iter
->second
);
68 bool SyncedSessionTracker::LookupSessionTab(
69 const std::string
& tag
,
70 SessionID::id_type tab_id
,
71 const SessionTab
** tab
) const {
73 SyncedTabMap::const_iterator tab_map_iter
= synced_tab_map_
.find(tag
);
74 if (tab_map_iter
== synced_tab_map_
.end()) {
75 // We have no record of this session.
79 IDToSessionTabMap::const_iterator tab_iter
=
80 tab_map_iter
->second
.find(tab_id
);
81 if (tab_iter
== tab_map_iter
->second
.end()) {
82 // We have no record of this tab.
86 *tab
= tab_iter
->second
.tab_ptr
;
90 SyncedSession
* SyncedSessionTracker::GetSession(
91 const std::string
& session_tag
) {
92 SyncedSession
* synced_session
= NULL
;
93 if (synced_session_map_
.find(session_tag
) !=
94 synced_session_map_
.end()) {
95 synced_session
= synced_session_map_
[session_tag
];
97 synced_session
= new SyncedSession
;
98 DVLOG(1) << "Creating new session with tag " << session_tag
<< " at "
100 synced_session
->session_tag
= session_tag
;
101 synced_session_map_
[session_tag
] = synced_session
;
103 DCHECK(synced_session
);
104 return synced_session
;
107 bool SyncedSessionTracker::DeleteSession(const std::string
& session_tag
) {
108 bool found_session
= false;
109 SyncedSessionMap::iterator iter
= synced_session_map_
.find(session_tag
);
110 if (iter
!= synced_session_map_
.end()) {
111 SyncedSession
* session
= iter
->second
;
112 synced_session_map_
.erase(iter
);
113 delete session
; // Delete the SyncedSession object.
114 found_session
= true;
116 synced_window_map_
.erase(session_tag
);
117 // It's possible there was no header node but there were tab nodes.
118 if (synced_tab_map_
.erase(session_tag
) > 0) {
119 found_session
= true;
121 return found_session
;
124 void SyncedSessionTracker::ResetSessionTracking(
125 const std::string
& session_tag
) {
126 // Reset window tracking.
127 GetSession(session_tag
)->windows
.clear();
128 SyncedWindowMap::iterator window_iter
= synced_window_map_
.find(session_tag
);
129 if (window_iter
!= synced_window_map_
.end()) {
130 for (IDToSessionWindowMap::iterator window_map_iter
=
131 window_iter
->second
.begin();
132 window_map_iter
!= window_iter
->second
.end(); ++window_map_iter
) {
133 window_map_iter
->second
.owned
= false;
134 // We clear out the tabs to prevent double referencing of the same tab.
135 // All tabs that are in use will be added back as needed.
136 window_map_iter
->second
.window_ptr
->tabs
.clear();
140 // Reset tab tracking.
141 SyncedTabMap::iterator tab_iter
= synced_tab_map_
.find(session_tag
);
142 if (tab_iter
!= synced_tab_map_
.end()) {
143 for (IDToSessionTabMap::iterator tab_map_iter
=
144 tab_iter
->second
.begin();
145 tab_map_iter
!= tab_iter
->second
.end(); ++tab_map_iter
) {
146 tab_map_iter
->second
.owned
= false;
151 bool SyncedSessionTracker::DeleteOldSessionWindowIfNecessary(
152 SessionWindowWrapper window_wrapper
) {
153 // Clear the tabs first, since we don't want the destructor to destroy
154 // them. Their deletion will be handled by DeleteOldSessionTab below.
155 if (!window_wrapper
.owned
) {
156 DVLOG(1) << "Deleting closed window "
157 << window_wrapper
.window_ptr
->window_id
.id();
158 window_wrapper
.window_ptr
->tabs
.clear();
159 delete window_wrapper
.window_ptr
;
165 bool SyncedSessionTracker::DeleteOldSessionTabIfNecessary(
166 SessionTabWrapper tab_wrapper
) {
167 if (!tab_wrapper
.owned
) {
169 SessionTab
* tab_ptr
= tab_wrapper
.tab_ptr
;
171 if (tab_ptr
->navigations
.size() > 0) {
172 title
= " (" + UTF16ToUTF8(
173 tab_ptr
->navigations
[tab_ptr
->navigations
.size()-1].title()) + ")";
175 DVLOG(1) << "Deleting closed tab " << tab_ptr
->tab_id
.id() << title
176 << " from window " << tab_ptr
->window_id
.id();
178 unmapped_tabs_
.erase(tab_wrapper
.tab_ptr
);
179 delete tab_wrapper
.tab_ptr
;
185 void SyncedSessionTracker::CleanupSession(const std::string
& session_tag
) {
186 // Go through and delete any windows or tabs without owners.
187 SyncedWindowMap::iterator window_iter
= synced_window_map_
.find(session_tag
);
188 if (window_iter
!= synced_window_map_
.end()) {
189 for (IDToSessionWindowMap::iterator iter
= window_iter
->second
.begin();
190 iter
!= window_iter
->second
.end();) {
191 SessionWindowWrapper window_wrapper
= iter
->second
;
192 if (DeleteOldSessionWindowIfNecessary(window_wrapper
))
193 window_iter
->second
.erase(iter
++);
199 SyncedTabMap::iterator tab_iter
= synced_tab_map_
.find(session_tag
);
200 if (tab_iter
!= synced_tab_map_
.end()) {
201 for (IDToSessionTabMap::iterator iter
= tab_iter
->second
.begin();
202 iter
!= tab_iter
->second
.end();) {
203 SessionTabWrapper tab_wrapper
= iter
->second
;
204 if (DeleteOldSessionTabIfNecessary(tab_wrapper
))
205 tab_iter
->second
.erase(iter
++);
212 void SyncedSessionTracker::PutWindowInSession(const std::string
& session_tag
,
213 SessionID::id_type window_id
) {
214 SessionWindow
* window_ptr
= NULL
;
215 IDToSessionWindowMap::iterator iter
=
216 synced_window_map_
[session_tag
].find(window_id
);
217 if (iter
!= synced_window_map_
[session_tag
].end()) {
218 iter
->second
.owned
= true;
219 window_ptr
= iter
->second
.window_ptr
;
220 DVLOG(1) << "Putting seen window " << window_id
<< " at " << window_ptr
221 << "in " << (session_tag
== local_session_tag_
?
222 "local session" : session_tag
);
224 // Create the window.
225 window_ptr
= new SessionWindow();
226 window_ptr
->window_id
.set_id(window_id
);
227 synced_window_map_
[session_tag
][window_id
] =
228 SessionWindowWrapper(window_ptr
, true);
229 DVLOG(1) << "Putting new window " << window_id
<< " at " << window_ptr
230 << "in " << (session_tag
== local_session_tag_
?
231 "local session" : session_tag
);
234 DCHECK_EQ(window_ptr
->window_id
.id(), window_id
);
235 DCHECK_EQ(reinterpret_cast<SessionWindow
*>(NULL
),
236 GetSession(session_tag
)->windows
[window_id
]);
237 GetSession(session_tag
)->windows
[window_id
] = window_ptr
;
240 void SyncedSessionTracker::PutTabInWindow(const std::string
& session_tag
,
241 SessionID::id_type window_id
,
242 SessionID::id_type tab_id
,
244 SessionTab
* tab_ptr
= GetTab(session_tag
, tab_id
);
245 unmapped_tabs_
.erase(tab_ptr
);
246 synced_tab_map_
[session_tag
][tab_id
].owned
= true;
247 tab_ptr
->window_id
.set_id(window_id
);
248 DVLOG(1) << " - tab " << tab_id
<< " added to window "<< window_id
;
249 DCHECK(GetSession(session_tag
)->windows
.find(window_id
) !=
250 GetSession(session_tag
)->windows
.end());
251 std::vector
<SessionTab
*>& window_tabs
=
252 GetSession(session_tag
)->windows
[window_id
]->tabs
;
253 if (window_tabs
.size() <= tab_index
) {
254 window_tabs
.resize(tab_index
+1, NULL
);
256 DCHECK(!window_tabs
[tab_index
]);
257 window_tabs
[tab_index
] = tab_ptr
;
260 SessionTab
* SyncedSessionTracker::GetTab(
261 const std::string
& session_tag
,
262 SessionID::id_type tab_id
) {
263 SessionTab
* tab_ptr
= NULL
;
264 IDToSessionTabMap::iterator iter
=
265 synced_tab_map_
[session_tag
].find(tab_id
);
266 if (iter
!= synced_tab_map_
[session_tag
].end()) {
267 tab_ptr
= iter
->second
.tab_ptr
;
270 if (tab_ptr
->navigations
.size() > 0) {
271 title
= " (" + UTF16ToUTF8(
272 tab_ptr
->navigations
[tab_ptr
->navigations
.size()-1].title()) + ")";
274 DVLOG(1) << "Getting "
275 << (session_tag
== local_session_tag_
?
276 "local session" : session_tag
)
277 << "'s seen tab " << tab_id
<< " at " << tab_ptr
<< title
;
280 tab_ptr
= new SessionTab();
281 tab_ptr
->tab_id
.set_id(tab_id
);
282 synced_tab_map_
[session_tag
][tab_id
] = SessionTabWrapper(tab_ptr
, false);
283 unmapped_tabs_
.insert(tab_ptr
);
284 DVLOG(1) << "Getting "
285 << (session_tag
== local_session_tag_
?
286 "local session" : session_tag
)
287 << "'s new tab " << tab_id
<< " at " << tab_ptr
;
290 DCHECK_EQ(tab_ptr
->tab_id
.id(), tab_id
);
294 void SyncedSessionTracker::Clear() {
295 // Delete SyncedSession objects (which also deletes all their windows/tabs).
296 STLDeleteValues(&synced_session_map_
);
298 // Go through and delete any tabs we had allocated but had not yet placed into
299 // a SyncedSessionobject.
300 STLDeleteElements(&unmapped_tabs_
);
302 // Get rid of our Window/Tab maps (does not delete the actual Window/Tabs
303 // themselves; they should have all been deleted above).
304 synced_window_map_
.clear();
305 synced_tab_map_
.clear();
307 local_session_tag_
.clear();
310 } // namespace browser_sync