// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/sync/glue/theme_model_associator.h" #include "base/basictypes.h" #include "base/logging.h" #include "base/utf_string_conversions.h" #include "chrome/browser/sync/engine/syncapi.h" #include "chrome/browser/sync/glue/sync_backend_host.h" #include "chrome/browser/sync/glue/theme_util.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/sync/protocol/theme_specifics.pb.h" namespace browser_sync { namespace { static const char kThemesTag[] = "google_chrome_themes"; static const char kCurrentThemeNodeTitle[] = "Current Theme"; static const char kNoThemesFolderError[] = "Server did not create the top-level themes node. We " "might be running against an out-of-date server."; } // namespace ThemeModelAssociator::ThemeModelAssociator( ProfileSyncService* sync_service) : sync_service_(sync_service) { DCHECK(sync_service_); } ThemeModelAssociator::~ThemeModelAssociator() {} bool ThemeModelAssociator::AssociateModels() { sync_api::WriteTransaction trans(sync_service_->GetUserShare()); sync_api::ReadNode root(&trans); if (!root.InitByTagLookup(kThemesTag)) { LOG(ERROR) << kNoThemesFolderError; return false; } Profile* profile = sync_service_->profile(); sync_api::WriteNode node(&trans); // TODO(akalin): When we have timestamps, we may want to do // something more intelligent than preferring the sync data over our // local data. if (node.InitByClientTagLookup(syncable::THEMES, kCurrentThemeClientTag)) { // Update the current theme from the sync data. // TODO(akalin): If the sync data does not have // use_system_theme_by_default and we do, update that flag on the // sync data. sync_pb::ThemeSpecifics theme_specifics = node.GetThemeSpecifics(); if (UpdateThemeSpecificsOrSetCurrentThemeIfNecessary(profile, &theme_specifics)) node.SetThemeSpecifics(theme_specifics); } else { // Set the sync data from the current theme. sync_api::WriteNode node(&trans); if (!node.InitUniqueByCreation(syncable::THEMES, root, kCurrentThemeClientTag)) { LOG(ERROR) << "Could not create current theme node."; return false; } node.SetIsFolder(false); node.SetTitle(UTF8ToWide(kCurrentThemeNodeTitle)); sync_pb::ThemeSpecifics theme_specifics; GetThemeSpecificsFromCurrentTheme(profile, &theme_specifics); node.SetThemeSpecifics(theme_specifics); } return true; } bool ThemeModelAssociator::DisassociateModels() { // We don't maintain any association state, so nothing to do. return true; } bool ThemeModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) { DCHECK(has_nodes); *has_nodes = false; sync_api::ReadTransaction trans(sync_service_->GetUserShare()); sync_api::ReadNode root(&trans); if (!root.InitByTagLookup(kThemesTag)) { LOG(ERROR) << kNoThemesFolderError; return false; } // The sync model has user created nodes iff the themes folder has // any children. *has_nodes = root.GetFirstChildId() != sync_api::kInvalidId; return true; } bool ThemeModelAssociator::CryptoReadyIfNecessary() { // We only access the cryptographer while holding a transaction. sync_api::ReadTransaction trans(sync_service_->GetUserShare()); syncable::ModelTypeSet encrypted_types; sync_service_->GetEncryptedDataTypes(&encrypted_types); return encrypted_types.count(syncable::THEMES) == 0 || sync_service_->IsCryptographerReady(&trans); } } // namespace browser_sync