OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/glue/session_change_processor.h" | 5 #include "chrome/browser/sync/glue/session_change_processor.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/scoped_vector.h" | 12 #include "base/scoped_vector.h" |
13 #include "chrome/browser/browser_thread.h" | |
14 #include "chrome/browser/sync/engine/syncapi.h" | 13 #include "chrome/browser/sync/engine/syncapi.h" |
15 #include "chrome/browser/sync/glue/session_model_associator.h" | 14 #include "chrome/browser/sync/glue/session_model_associator.h" |
| 15 #include "chrome/browser/tab_contents/navigation_controller.h" |
| 16 #include "chrome/browser/tab_contents/tab_contents.h" |
16 #include "chrome/common/notification_details.h" | 17 #include "chrome/common/notification_details.h" |
17 #include "chrome/common/notification_service.h" | 18 #include "chrome/common/notification_service.h" |
18 #include "chrome/common/notification_source.h" | 19 #include "chrome/common/notification_source.h" |
19 | 20 |
20 namespace browser_sync { | 21 namespace browser_sync { |
21 | 22 |
22 SessionChangeProcessor::SessionChangeProcessor( | 23 SessionChangeProcessor::SessionChangeProcessor( |
23 UnrecoverableErrorHandler* error_handler, | 24 UnrecoverableErrorHandler* error_handler, |
24 SessionModelAssociator* session_model_associator) | 25 SessionModelAssociator* session_model_associator) |
25 : ChangeProcessor(error_handler), | 26 : ChangeProcessor(error_handler), |
26 session_model_associator_(session_model_associator), | 27 session_model_associator_(session_model_associator), |
27 profile_(NULL) { | 28 profile_(NULL) { |
28 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 29 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
29 DCHECK(error_handler); | 30 DCHECK(error_handler); |
30 DCHECK(session_model_associator_); | 31 DCHECK(session_model_associator_); |
31 } | 32 } |
32 | 33 |
33 SessionChangeProcessor::~SessionChangeProcessor() { | 34 SessionChangeProcessor::~SessionChangeProcessor() { |
34 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 35 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
35 } | 36 } |
36 | 37 |
37 void SessionChangeProcessor::Observe(NotificationType type, | 38 void SessionChangeProcessor::Observe(NotificationType type, |
38 const NotificationSource& source, | 39 const NotificationSource& source, |
39 const NotificationDetails& details) { | 40 const NotificationDetails& details) { |
40 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
41 DCHECK(running()); | 42 DCHECK(running()); |
42 DCHECK(profile_); | 43 DCHECK(profile_); |
| 44 |
| 45 // Track which windows and/or tabs are modified. |
| 46 std::vector<TabContents*> modified_tabs; |
| 47 bool windows_changed = false; |
43 switch (type.value) { | 48 switch (type.value) { |
44 case NotificationType::SESSION_SERVICE_SAVED: { | 49 case NotificationType::BROWSER_OPENED: { |
45 std::string tag = session_model_associator_->GetCurrentMachineTag(); | 50 Browser* browser = Source<Browser>(source).ptr(); |
46 DCHECK_EQ(Source<Profile>(source).ptr(), profile_); | 51 if (browser->profile() != profile_) { |
47 session_model_associator_->UpdateSyncModelDataFromClient(); | 52 return; |
| 53 } |
| 54 |
| 55 windows_changed = true; |
| 56 break; |
| 57 } |
| 58 |
| 59 case NotificationType::TAB_PARENTED: { |
| 60 NavigationController* controller = |
| 61 Source<NavigationController>(source).ptr(); |
| 62 if (controller->profile() != profile_) { |
| 63 return; |
| 64 } |
| 65 windows_changed = true; |
| 66 modified_tabs.push_back(controller->tab_contents()); |
| 67 break; |
| 68 } |
| 69 |
| 70 case NotificationType::TAB_CLOSED: { |
| 71 NavigationController* controller = |
| 72 Source<NavigationController>(source).ptr(); |
| 73 if (controller->profile() != profile_) { |
| 74 return; |
| 75 } |
| 76 windows_changed = true; |
| 77 modified_tabs.push_back(controller->tab_contents()); |
| 78 break; |
| 79 } |
| 80 |
| 81 case NotificationType::NAV_LIST_PRUNED: { |
| 82 NavigationController* controller = |
| 83 Source<NavigationController>(source).ptr(); |
| 84 if (controller->profile() != profile_) { |
| 85 return; |
| 86 } |
| 87 modified_tabs.push_back(controller->tab_contents()); |
| 88 break; |
| 89 } |
| 90 |
| 91 case NotificationType::NAV_ENTRY_CHANGED: { |
| 92 NavigationController* controller = |
| 93 Source<NavigationController>(source).ptr(); |
| 94 if (controller->profile() != profile_) { |
| 95 return; |
| 96 } |
| 97 modified_tabs.push_back(controller->tab_contents()); |
| 98 break; |
| 99 } |
| 100 |
| 101 case NotificationType::NAV_ENTRY_COMMITTED: { |
| 102 NavigationController* controller = |
| 103 Source<NavigationController>(source).ptr(); |
| 104 if (controller->profile() != profile_) { |
| 105 return; |
| 106 } |
| 107 modified_tabs.push_back(controller->tab_contents()); |
| 108 break; |
| 109 } |
| 110 |
| 111 case NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED: { |
| 112 TabContents* tab_contents = Source<TabContents>(source).ptr(); |
| 113 DCHECK(tab_contents); |
| 114 if (tab_contents->profile() != profile_) { |
| 115 return; |
| 116 } |
| 117 if (tab_contents->extension_app()) { |
| 118 modified_tabs.push_back(tab_contents); |
| 119 } |
48 break; | 120 break; |
49 } | 121 } |
50 default: | 122 default: |
51 LOG(DFATAL) << "Received unexpected notification of type " | 123 LOG(ERROR) << "Received unexpected notification of type " |
52 << type.value; | 124 << type.value; |
53 break; | 125 break; |
54 } | 126 } |
| 127 |
| 128 // Associate windows first to ensure tabs have homes. |
| 129 if (windows_changed) |
| 130 session_model_associator_->ReassociateWindows(false); |
| 131 if (!modified_tabs.empty()) |
| 132 session_model_associator_->ReassociateTabs(modified_tabs); |
55 } | 133 } |
56 | 134 |
57 void SessionChangeProcessor::ApplyChangesFromSyncModel( | 135 void SessionChangeProcessor::ApplyChangesFromSyncModel( |
58 const sync_api::BaseTransaction* trans, | 136 const sync_api::BaseTransaction* trans, |
59 const sync_api::SyncManager::ChangeRecord* changes, | 137 const sync_api::SyncManager::ChangeRecord* changes, |
60 int change_count) { | 138 int change_count) { |
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
62 if (!running()) { | 140 if (!running()) { |
63 return; | 141 return; |
64 } | 142 } |
65 | 143 |
66 StopObserving(); | 144 StopObserving(); |
67 | 145 |
68 // This currently ignores the tracked changes and rebuilds the sessions from | 146 sync_api::ReadNode root(trans); |
69 // all the session sync nodes. | 147 if (!root.InitByTagLookup(kSessionsTag)) { |
70 // TODO(zea): Make use of |changes| to adjust only modified sessions. | 148 error_handler()->OnUnrecoverableError(FROM_HERE, |
71 session_model_associator_->UpdateFromSyncModel(trans); | 149 "Sessions root node lookup failed."); |
| 150 return; |
| 151 } |
| 152 |
| 153 for (int i = 0; i < change_count; ++i) { |
| 154 const sync_api::SyncManager::ChangeRecord& change = changes[i]; |
| 155 sync_api::SyncManager::ChangeRecord::Action action(change.action); |
| 156 if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == action) { |
| 157 // Deletions should only be for a foreign client itself, and hence affect |
| 158 // the header node, never a tab node. |
| 159 sync_api::ReadNode node(trans); |
| 160 if (!node.InitByIdLookup(change.id)) { |
| 161 error_handler()->OnUnrecoverableError(FROM_HERE, |
| 162 "Session node lookup failed."); |
| 163 return; |
| 164 } |
| 165 DCHECK_EQ(node.GetModelType(), syncable::SESSIONS); |
| 166 const sync_pb::SessionSpecifics& specifics = node.GetSessionSpecifics(); |
| 167 session_model_associator_->DisassociateForeignSession( |
| 168 specifics.session_tag()); |
| 169 continue; |
| 170 } |
| 171 |
| 172 // Handle an update or add. |
| 173 sync_api::ReadNode sync_node(trans); |
| 174 if (!sync_node.InitByIdLookup(change.id)) { |
| 175 error_handler()->OnUnrecoverableError(FROM_HERE, |
| 176 "Session node lookup failed."); |
| 177 return; |
| 178 } |
| 179 |
| 180 // Check that the changed node is a child of the session folder. |
| 181 DCHECK(root.GetId() == sync_node.GetParentId()); |
| 182 DCHECK(syncable::SESSIONS == sync_node.GetModelType()); |
| 183 |
| 184 const sync_pb::SessionSpecifics& specifics( |
| 185 sync_node.GetSessionSpecifics()); |
| 186 const int64 mtime = sync_node.GetModificationTime(); |
| 187 // Model associator handles foreign session update and add the same. |
| 188 session_model_associator_->AssociateForeignSpecifics(specifics, mtime); |
| 189 } |
72 | 190 |
73 // Notify foreign session handlers that there are new sessions. | 191 // Notify foreign session handlers that there are new sessions. |
74 NotificationService::current()->Notify( | 192 NotificationService::current()->Notify( |
75 NotificationType::FOREIGN_SESSION_UPDATED, | 193 NotificationType::FOREIGN_SESSION_UPDATED, |
76 NotificationService::AllSources(), | 194 NotificationService::AllSources(), |
77 NotificationService::NoDetails()); | 195 NotificationService::NoDetails()); |
78 | 196 |
79 StartObserving(); | 197 StartObserving(); |
80 } | 198 } |
81 | 199 |
82 void SessionChangeProcessor::StartImpl(Profile* profile) { | 200 void SessionChangeProcessor::StartImpl(Profile* profile) { |
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
84 DCHECK(profile); | 202 DCHECK(profile); |
85 DCHECK(profile_ == NULL); | 203 DCHECK(profile_ == NULL); |
86 profile_ = profile; | 204 profile_ = profile; |
87 StartObserving(); | 205 StartObserving(); |
88 } | 206 } |
89 | 207 |
90 void SessionChangeProcessor::StopImpl() { | 208 void SessionChangeProcessor::StopImpl() { |
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
92 StopObserving(); | 210 StopObserving(); |
93 profile_ = NULL; | 211 profile_ = NULL; |
94 } | 212 } |
95 | 213 |
96 void SessionChangeProcessor::StartObserving() { | 214 void SessionChangeProcessor::StartObserving() { |
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
98 DCHECK(profile_); | 216 DCHECK(profile_); |
99 notification_registrar_.Add( | 217 notification_registrar_.Add(this, NotificationType::TAB_PARENTED, |
100 this, NotificationType::SESSION_SERVICE_SAVED, | 218 NotificationService::AllSources()); |
101 Source<Profile>(profile_)); | 219 notification_registrar_.Add(this, NotificationType::TAB_CLOSED, |
| 220 NotificationService::AllSources()); |
| 221 notification_registrar_.Add(this, NotificationType::NAV_LIST_PRUNED, |
| 222 NotificationService::AllSources()); |
| 223 notification_registrar_.Add(this, NotificationType::NAV_ENTRY_CHANGED, |
| 224 NotificationService::AllSources()); |
| 225 notification_registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, |
| 226 NotificationService::AllSources()); |
| 227 notification_registrar_.Add(this, NotificationType::BROWSER_OPENED, |
| 228 NotificationService::AllSources()); |
| 229 notification_registrar_.Add(this, |
| 230 NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, |
| 231 NotificationService::AllSources()); |
102 } | 232 } |
103 | 233 |
104 void SessionChangeProcessor::StopObserving() { | 234 void SessionChangeProcessor::StopObserving() { |
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
106 DCHECK(profile_); | 236 DCHECK(profile_); |
107 notification_registrar_.RemoveAll(); | 237 notification_registrar_.RemoveAll(); |
108 } | 238 } |
109 | 239 |
110 } // namespace browser_sync | 240 } // namespace browser_sync |
OLD | NEW |