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 "chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h"
7 #include "base/lazy_instance.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/values.h"
10 #include "chrome/browser/bookmarks/bookmark_model.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/common/pref_names.h"
13 #include "components/user_prefs/pref_registry_syncable.h"
14 #include "content/public/browser/browser_thread.h"
16 using content::BrowserThread;
20 // PartnerModelKeeper is used as a singleton to store an immutable hierarchy
21 // of partner bookmarks. The hierarchy is retrieved from the partner bookmarks
22 // provider and doesn't depend on the user profile.
23 // The retrieved hierarchy persists
24 // PartnerBookmarksShim is responsible to applying and storing the user changes
25 // (deletions/renames) in the user profile, thus keeping the hierarchy intact.
26 struct PartnerModelKeeper {
27 scoped_ptr<BookmarkNode> partner_bookmarks_root;
34 base::LazyInstance<PartnerModelKeeper> g_partner_model_keeper =
35 LAZY_INSTANCE_INITIALIZER;
37 const void* kPartnerBookmarksShimUserDataKey =
38 &kPartnerBookmarksShimUserDataKey;
40 // Dictionary keys for entries in the kPartnerBookmarksMapping pref.
41 static const char kMappingUrl[] = "url";
42 static const char kMappingProviderTitle[] = "provider_title";
43 static const char kMappingTitle[] = "mapped_title";
48 PartnerBookmarksShim* PartnerBookmarksShim::BuildForBrowserContext(
49 content::BrowserContext* browser_context) {
50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52 PartnerBookmarksShim* data =
53 reinterpret_cast<PartnerBookmarksShim*>(
54 browser_context->GetUserData(kPartnerBookmarksShimUserDataKey));
58 data = new PartnerBookmarksShim(
59 Profile::FromBrowserContext(browser_context)->GetPrefs());
60 browser_context->SetUserData(kPartnerBookmarksShimUserDataKey, data);
61 data->ReloadNodeMapping();
66 void PartnerBookmarksShim::RegisterProfilePrefs(
67 user_prefs::PrefRegistrySyncable* registry) {
68 registry->RegisterListPref(
69 prefs::kPartnerBookmarkMappings,
70 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
73 bool PartnerBookmarksShim::IsLoaded() const {
74 return g_partner_model_keeper.Get().loaded;
77 bool PartnerBookmarksShim::HasPartnerBookmarks() const {
79 return g_partner_model_keeper.Get().partner_bookmarks_root.get() != NULL;
82 bool PartnerBookmarksShim::IsReachable(const BookmarkNode* node) const {
83 DCHECK(IsPartnerBookmark(node));
84 if (!HasPartnerBookmarks())
86 for (const BookmarkNode* i = node; i != NULL; i = i->parent()) {
87 const NodeRenamingMapKey key(i->url(), i->GetTitle());
88 NodeRenamingMap::const_iterator remap = node_rename_remove_map_.find(key);
89 if (remap != node_rename_remove_map_.end() && remap->second.empty())
95 void PartnerBookmarksShim::RemoveBookmark(const BookmarkNode* node) {
96 RenameBookmark(node, base::string16());
99 void PartnerBookmarksShim::RenameBookmark(const BookmarkNode* node,
100 const base::string16& title) {
101 const NodeRenamingMapKey key(node->url(), node->GetTitle());
102 node_rename_remove_map_[key] = title;
104 FOR_EACH_OBSERVER(PartnerBookmarksShim::Observer, observers_,
105 PartnerShimChanged(this));
108 void PartnerBookmarksShim::AddObserver(
109 PartnerBookmarksShim::Observer* observer) {
110 observers_.AddObserver(observer);
113 void PartnerBookmarksShim::RemoveObserver(
114 PartnerBookmarksShim::Observer* observer) {
115 observers_.RemoveObserver(observer);
118 const BookmarkNode* PartnerBookmarksShim::GetNodeByID(int64 id) const {
120 if (!HasPartnerBookmarks())
122 return GetNodeByID(GetPartnerBookmarksRoot(), id);
125 base::string16 PartnerBookmarksShim::GetTitle(const BookmarkNode* node) const {
127 DCHECK(IsPartnerBookmark(node));
129 const NodeRenamingMapKey key(node->url(), node->GetTitle());
130 NodeRenamingMap::const_iterator i = node_rename_remove_map_.find(key);
131 if (i != node_rename_remove_map_.end())
134 return node->GetTitle();
137 bool PartnerBookmarksShim::IsPartnerBookmark(const BookmarkNode* node) const {
139 if (!HasPartnerBookmarks())
141 const BookmarkNode* parent = node;
143 if (parent == GetPartnerBookmarksRoot())
145 parent = parent->parent();
150 const BookmarkNode* PartnerBookmarksShim::GetPartnerBookmarksRoot() const {
151 return g_partner_model_keeper.Get().partner_bookmarks_root.get();
154 void PartnerBookmarksShim::SetPartnerBookmarksRoot(BookmarkNode* root_node) {
155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
156 g_partner_model_keeper.Get().partner_bookmarks_root.reset(root_node);
157 g_partner_model_keeper.Get().loaded = true;
158 FOR_EACH_OBSERVER(PartnerBookmarksShim::Observer, observers_,
159 PartnerShimLoaded(this));
162 PartnerBookmarksShim::NodeRenamingMapKey::NodeRenamingMapKey(
163 const GURL& url, const base::string16& provider_title)
164 : url_(url), provider_title_(provider_title) {}
166 PartnerBookmarksShim::NodeRenamingMapKey::~NodeRenamingMapKey() {}
168 bool operator<(const PartnerBookmarksShim::NodeRenamingMapKey& a,
169 const PartnerBookmarksShim::NodeRenamingMapKey& b) {
170 return (a.url_ < b.url_) ||
171 (a.url_ == b.url_ && a.provider_title_ < b.provider_title_);
175 void PartnerBookmarksShim::ClearInBrowserContextForTesting(
176 content::BrowserContext* browser_context) {
177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
178 browser_context->SetUserData(kPartnerBookmarksShimUserDataKey, 0);
182 void PartnerBookmarksShim::ClearPartnerModelForTesting() {
183 g_partner_model_keeper.Get().loaded = false;
184 g_partner_model_keeper.Get().partner_bookmarks_root.reset(0);
187 PartnerBookmarksShim::PartnerBookmarksShim(PrefService* prefs)
190 ObserverList<PartnerBookmarksShim::Observer>::NOTIFY_EXISTING_ONLY) {
193 PartnerBookmarksShim::~PartnerBookmarksShim() {
194 FOR_EACH_OBSERVER(PartnerBookmarksShim::Observer, observers_,
195 ShimBeingDeleted(this));
198 const BookmarkNode* PartnerBookmarksShim::GetNodeByID(
199 const BookmarkNode* parent, int64 id) const {
200 if (parent->id() == id)
202 for (int i = 0, child_count = parent->child_count(); i < child_count; ++i) {
203 const BookmarkNode* result = GetNodeByID(parent->GetChild(i), id);
210 void PartnerBookmarksShim::ReloadNodeMapping() {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
213 node_rename_remove_map_.clear();
217 const base::ListValue* list =
218 prefs_->GetList(prefs::kPartnerBookmarkMappings);
222 for (base::ListValue::const_iterator it = list->begin();
223 it != list->end(); ++it) {
224 const base::DictionaryValue* dict = NULL;
225 if (!*it || !(*it)->GetAsDictionary(&dict)) {
231 base::string16 provider_title;
232 base::string16 mapped_title;
233 if (!dict->GetString(kMappingUrl, &url) ||
234 !dict->GetString(kMappingProviderTitle, &provider_title) ||
235 !dict->GetString(kMappingTitle, &mapped_title)) {
240 const NodeRenamingMapKey key(GURL(url), provider_title);
241 node_rename_remove_map_[key] = mapped_title;
245 void PartnerBookmarksShim::SaveNodeMapping() {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
250 base::ListValue list;
251 for (NodeRenamingMap::const_iterator i = node_rename_remove_map_.begin();
252 i != node_rename_remove_map_.end();
254 base::DictionaryValue* dict = new base::DictionaryValue();
255 dict->SetString(kMappingUrl, i->first.url().spec());
256 dict->SetString(kMappingProviderTitle, i->first.provider_title());
257 dict->SetString(kMappingTitle, i->second);
260 prefs_->Set(prefs::kPartnerBookmarkMappings, list);