| Index: chrome/browser/sync/glue/session_change_processor.cc
|
| ===================================================================
|
| --- chrome/browser/sync/glue/session_change_processor.cc (revision 70604)
|
| +++ chrome/browser/sync/glue/session_change_processor.cc (working copy)
|
| @@ -10,9 +10,10 @@
|
|
|
| #include "base/logging.h"
|
| #include "base/scoped_vector.h"
|
| -#include "chrome/browser/browser_thread.h"
|
| #include "chrome/browser/sync/engine/syncapi.h"
|
| #include "chrome/browser/sync/glue/session_model_associator.h"
|
| +#include "chrome/browser/tab_contents/navigation_controller.h"
|
| +#include "chrome/browser/tab_contents/tab_contents.h"
|
| #include "chrome/common/notification_details.h"
|
| #include "chrome/common/notification_service.h"
|
| #include "chrome/common/notification_source.h"
|
| @@ -40,18 +41,95 @@
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| DCHECK(running());
|
| DCHECK(profile_);
|
| +
|
| + // Track which windows and/or tabs are modified.
|
| + std::vector<TabContents*> modified_tabs;
|
| + bool windows_changed = false;
|
| switch (type.value) {
|
| - case NotificationType::SESSION_SERVICE_SAVED: {
|
| - std::string tag = session_model_associator_->GetCurrentMachineTag();
|
| - DCHECK_EQ(Source<Profile>(source).ptr(), profile_);
|
| - session_model_associator_->UpdateSyncModelDataFromClient();
|
| + case NotificationType::BROWSER_OPENED: {
|
| + Browser* browser = Source<Browser>(source).ptr();
|
| + if (browser->profile() != profile_) {
|
| + return;
|
| + }
|
| +
|
| + windows_changed = true;
|
| break;
|
| }
|
| +
|
| + case NotificationType::TAB_PARENTED: {
|
| + NavigationController* controller =
|
| + Source<NavigationController>(source).ptr();
|
| + if (controller->profile() != profile_) {
|
| + return;
|
| + }
|
| + windows_changed = true;
|
| + modified_tabs.push_back(controller->tab_contents());
|
| + break;
|
| + }
|
| +
|
| + case NotificationType::TAB_CLOSED: {
|
| + NavigationController* controller =
|
| + Source<NavigationController>(source).ptr();
|
| + if (controller->profile() != profile_) {
|
| + return;
|
| + }
|
| + windows_changed = true;
|
| + modified_tabs.push_back(controller->tab_contents());
|
| + break;
|
| + }
|
| +
|
| + case NotificationType::NAV_LIST_PRUNED: {
|
| + NavigationController* controller =
|
| + Source<NavigationController>(source).ptr();
|
| + if (controller->profile() != profile_) {
|
| + return;
|
| + }
|
| + modified_tabs.push_back(controller->tab_contents());
|
| + break;
|
| + }
|
| +
|
| + case NotificationType::NAV_ENTRY_CHANGED: {
|
| + NavigationController* controller =
|
| + Source<NavigationController>(source).ptr();
|
| + if (controller->profile() != profile_) {
|
| + return;
|
| + }
|
| + modified_tabs.push_back(controller->tab_contents());
|
| + break;
|
| + }
|
| +
|
| + case NotificationType::NAV_ENTRY_COMMITTED: {
|
| + NavigationController* controller =
|
| + Source<NavigationController>(source).ptr();
|
| + if (controller->profile() != profile_) {
|
| + return;
|
| + }
|
| + modified_tabs.push_back(controller->tab_contents());
|
| + break;
|
| + }
|
| +
|
| + case NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED: {
|
| + TabContents* tab_contents = Source<TabContents>(source).ptr();
|
| + DCHECK(tab_contents);
|
| + if (tab_contents->profile() != profile_) {
|
| + return;
|
| + }
|
| + if (tab_contents->extension_app()) {
|
| + modified_tabs.push_back(tab_contents);
|
| + }
|
| + break;
|
| + }
|
| default:
|
| - LOG(DFATAL) << "Received unexpected notification of type "
|
| + LOG(ERROR) << "Received unexpected notification of type "
|
| << type.value;
|
| break;
|
| }
|
| +
|
| + // Associate windows first to ensure tabs have homes.
|
| + if (windows_changed)
|
| + session_model_associator_->ReassociateWindows(false);
|
| + if (!modified_tabs.empty())
|
| + session_model_associator_->ReassociateTabs(modified_tabs);
|
| }
|
|
|
| void SessionChangeProcessor::ApplyChangesFromSyncModel(
|
| @@ -65,11 +143,51 @@
|
|
|
| StopObserving();
|
|
|
| - // This currently ignores the tracked changes and rebuilds the sessions from
|
| - // all the session sync nodes.
|
| - // TODO(zea): Make use of |changes| to adjust only modified sessions.
|
| - session_model_associator_->UpdateFromSyncModel(trans);
|
| + sync_api::ReadNode root(trans);
|
| + if (!root.InitByTagLookup(kSessionsTag)) {
|
| + error_handler()->OnUnrecoverableError(FROM_HERE,
|
| + "Sessions root node lookup failed.");
|
| + return;
|
| + }
|
|
|
| + for (int i = 0; i < change_count; ++i) {
|
| + const sync_api::SyncManager::ChangeRecord& change = changes[i];
|
| + sync_api::SyncManager::ChangeRecord::Action action(change.action);
|
| + if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == action) {
|
| + // Deletions should only be for a foreign client itself, and hence affect
|
| + // the header node, never a tab node.
|
| + sync_api::ReadNode node(trans);
|
| + if (!node.InitByIdLookup(change.id)) {
|
| + error_handler()->OnUnrecoverableError(FROM_HERE,
|
| + "Session node lookup failed.");
|
| + return;
|
| + }
|
| + DCHECK_EQ(node.GetModelType(), syncable::SESSIONS);
|
| + const sync_pb::SessionSpecifics& specifics = node.GetSessionSpecifics();
|
| + session_model_associator_->DisassociateForeignSession(
|
| + specifics.session_tag());
|
| + continue;
|
| + }
|
| +
|
| + // Handle an update or add.
|
| + sync_api::ReadNode sync_node(trans);
|
| + if (!sync_node.InitByIdLookup(change.id)) {
|
| + error_handler()->OnUnrecoverableError(FROM_HERE,
|
| + "Session node lookup failed.");
|
| + return;
|
| + }
|
| +
|
| + // Check that the changed node is a child of the session folder.
|
| + DCHECK(root.GetId() == sync_node.GetParentId());
|
| + DCHECK(syncable::SESSIONS == sync_node.GetModelType());
|
| +
|
| + const sync_pb::SessionSpecifics& specifics(
|
| + sync_node.GetSessionSpecifics());
|
| + const int64 mtime = sync_node.GetModificationTime();
|
| + // Model associator handles foreign session update and add the same.
|
| + session_model_associator_->AssociateForeignSpecifics(specifics, mtime);
|
| + }
|
| +
|
| // Notify foreign session handlers that there are new sessions.
|
| NotificationService::current()->Notify(
|
| NotificationType::FOREIGN_SESSION_UPDATED,
|
| @@ -96,9 +214,21 @@
|
| void SessionChangeProcessor::StartObserving() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| DCHECK(profile_);
|
| - notification_registrar_.Add(
|
| - this, NotificationType::SESSION_SERVICE_SAVED,
|
| - Source<Profile>(profile_));
|
| + notification_registrar_.Add(this, NotificationType::TAB_PARENTED,
|
| + NotificationService::AllSources());
|
| + notification_registrar_.Add(this, NotificationType::TAB_CLOSED,
|
| + NotificationService::AllSources());
|
| + notification_registrar_.Add(this, NotificationType::NAV_LIST_PRUNED,
|
| + NotificationService::AllSources());
|
| + notification_registrar_.Add(this, NotificationType::NAV_ENTRY_CHANGED,
|
| + NotificationService::AllSources());
|
| + notification_registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
|
| + NotificationService::AllSources());
|
| + notification_registrar_.Add(this, NotificationType::BROWSER_OPENED,
|
| + NotificationService::AllSources());
|
| + notification_registrar_.Add(this,
|
| + NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
|
| + NotificationService::AllSources());
|
| }
|
|
|
| void SessionChangeProcessor::StopObserving() {
|
|
|