1 // Copyright (c) 2011 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 #include "chrome/browser/sync/glue/theme_model_associator.h" 6 7 #include "base/basictypes.h" 8 #include "base/logging.h" 9 #include "base/utf_string_conversions.h" 10 #include "chrome/browser/sync/engine/syncapi.h" 11 #include "chrome/browser/sync/glue/sync_backend_host.h" 12 #include "chrome/browser/sync/glue/theme_util.h" 13 #include "chrome/browser/sync/profile_sync_service.h" 14 #include "chrome/browser/sync/protocol/theme_specifics.pb.h" 15 16 namespace browser_sync { 17 18 namespace { 19 20 static const char kThemesTag[] = "google_chrome_themes"; 21 static const char kCurrentThemeNodeTitle[] = "Current Theme"; 22 23 static const char kNoThemesFolderError[] = 24 "Server did not create the top-level themes node. We " 25 "might be running against an out-of-date server."; 26 27 } // namespace 28 29 ThemeModelAssociator::ThemeModelAssociator( 30 ProfileSyncService* sync_service) 31 : sync_service_(sync_service) { 32 DCHECK(sync_service_); 33 } 34 35 ThemeModelAssociator::~ThemeModelAssociator() {} 36 37 bool ThemeModelAssociator::AssociateModels() { 38 sync_api::WriteTransaction trans(sync_service_->GetUserShare()); 39 sync_api::ReadNode root(&trans); 40 if (!root.InitByTagLookup(kThemesTag)) { 41 LOG(ERROR) << kNoThemesFolderError; 42 return false; 43 } 44 45 Profile* profile = sync_service_->profile(); 46 sync_api::WriteNode node(&trans); 47 // TODO(akalin): When we have timestamps, we may want to do 48 // something more intelligent than preferring the sync data over our 49 // local data. 50 if (node.InitByClientTagLookup(syncable::THEMES, kCurrentThemeClientTag)) { 51 // Update the current theme from the sync data. 52 // TODO(akalin): If the sync data does not have 53 // use_system_theme_by_default and we do, update that flag on the 54 // sync data. 55 sync_pb::ThemeSpecifics theme_specifics = node.GetThemeSpecifics(); 56 if (UpdateThemeSpecificsOrSetCurrentThemeIfNecessary(profile, 57 &theme_specifics)) 58 node.SetThemeSpecifics(theme_specifics); 59 } else { 60 // Set the sync data from the current theme. 61 sync_api::WriteNode node(&trans); 62 if (!node.InitUniqueByCreation(syncable::THEMES, root, 63 kCurrentThemeClientTag)) { 64 LOG(ERROR) << "Could not create current theme node."; 65 return false; 66 } 67 node.SetIsFolder(false); 68 node.SetTitle(UTF8ToWide(kCurrentThemeNodeTitle)); 69 sync_pb::ThemeSpecifics theme_specifics; 70 GetThemeSpecificsFromCurrentTheme(profile, &theme_specifics); 71 node.SetThemeSpecifics(theme_specifics); 72 } 73 return true; 74 } 75 76 bool ThemeModelAssociator::DisassociateModels() { 77 // We don't maintain any association state, so nothing to do. 78 return true; 79 } 80 81 bool ThemeModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) { 82 DCHECK(has_nodes); 83 *has_nodes = false; 84 sync_api::ReadTransaction trans(sync_service_->GetUserShare()); 85 sync_api::ReadNode root(&trans); 86 if (!root.InitByTagLookup(kThemesTag)) { 87 LOG(ERROR) << kNoThemesFolderError; 88 return false; 89 } 90 // The sync model has user created nodes iff the themes folder has 91 // any children. 92 *has_nodes = root.GetFirstChildId() != sync_api::kInvalidId; 93 return true; 94 } 95 96 bool ThemeModelAssociator::CryptoReadyIfNecessary() { 97 // We only access the cryptographer while holding a transaction. 98 sync_api::ReadTransaction trans(sync_service_->GetUserShare()); 99 syncable::ModelTypeSet encrypted_types; 100 sync_service_->GetEncryptedDataTypes(&encrypted_types); 101 return encrypted_types.count(syncable::THEMES) == 0 || 102 sync_service_->IsCryptographerReady(&trans); 103 } 104 105 } // namespace browser_sync 106