- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / ntp / android / partner_bookmarks_shim.cc
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.
4
5 #include "chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h"
6
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"
15
16 using content::BrowserThread;
17
18 namespace {
19
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;
28   bool loaded;
29
30   PartnerModelKeeper()
31     : loaded(false) {}
32 };
33
34 base::LazyInstance<PartnerModelKeeper> g_partner_model_keeper =
35     LAZY_INSTANCE_INITIALIZER;
36
37 const void* kPartnerBookmarksShimUserDataKey =
38     &kPartnerBookmarksShimUserDataKey;
39
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";
44
45 }  // namespace
46
47 // static
48 PartnerBookmarksShim* PartnerBookmarksShim::BuildForBrowserContext(
49     content::BrowserContext* browser_context) {
50   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
51
52   PartnerBookmarksShim* data =
53       reinterpret_cast<PartnerBookmarksShim*>(
54           browser_context->GetUserData(kPartnerBookmarksShimUserDataKey));
55   if (data)
56     return data;
57
58   data = new PartnerBookmarksShim(
59       Profile::FromBrowserContext(browser_context)->GetPrefs());
60   browser_context->SetUserData(kPartnerBookmarksShimUserDataKey, data);
61   data->ReloadNodeMapping();
62   return data;
63 }
64
65 // static
66 void PartnerBookmarksShim::RegisterProfilePrefs(
67     user_prefs::PrefRegistrySyncable* registry) {
68   registry->RegisterListPref(
69       prefs::kPartnerBookmarkMappings,
70       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
71 }
72
73 bool PartnerBookmarksShim::IsLoaded() const {
74   return g_partner_model_keeper.Get().loaded;
75 }
76
77 bool PartnerBookmarksShim::HasPartnerBookmarks() const {
78   DCHECK(IsLoaded());
79   return g_partner_model_keeper.Get().partner_bookmarks_root.get() != NULL;
80 }
81
82 bool PartnerBookmarksShim::IsReachable(const BookmarkNode* node) const {
83   DCHECK(IsPartnerBookmark(node));
84   if (!HasPartnerBookmarks())
85     return false;
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())
90       return false;
91   }
92   return true;
93 }
94
95 void PartnerBookmarksShim::RemoveBookmark(const BookmarkNode* node) {
96   RenameBookmark(node, base::string16());
97 }
98
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;
103   SaveNodeMapping();
104   FOR_EACH_OBSERVER(PartnerBookmarksShim::Observer, observers_,
105                     PartnerShimChanged(this));
106 }
107
108 void PartnerBookmarksShim::AddObserver(
109     PartnerBookmarksShim::Observer* observer) {
110   observers_.AddObserver(observer);
111 }
112
113 void PartnerBookmarksShim::RemoveObserver(
114     PartnerBookmarksShim::Observer* observer) {
115   observers_.RemoveObserver(observer);
116 }
117
118 const BookmarkNode* PartnerBookmarksShim::GetNodeByID(int64 id) const {
119   DCHECK(IsLoaded());
120   if (!HasPartnerBookmarks())
121     return NULL;
122   return GetNodeByID(GetPartnerBookmarksRoot(), id);
123 }
124
125 base::string16 PartnerBookmarksShim::GetTitle(const BookmarkNode* node) const {
126   DCHECK(node);
127   DCHECK(IsPartnerBookmark(node));
128
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())
132     return i->second;
133
134   return node->GetTitle();
135 }
136
137 bool PartnerBookmarksShim::IsPartnerBookmark(const BookmarkNode* node) const {
138   DCHECK(IsLoaded());
139   if (!HasPartnerBookmarks())
140     return false;
141   const BookmarkNode* parent = node;
142   while (parent) {
143     if (parent == GetPartnerBookmarksRoot())
144       return true;
145     parent = parent->parent();
146   }
147   return false;
148 }
149
150 const BookmarkNode* PartnerBookmarksShim::GetPartnerBookmarksRoot() const {
151   return g_partner_model_keeper.Get().partner_bookmarks_root.get();
152 }
153
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));
160 }
161
162 PartnerBookmarksShim::NodeRenamingMapKey::NodeRenamingMapKey(
163     const GURL& url, const base::string16& provider_title)
164     : url_(url), provider_title_(provider_title) {}
165
166 PartnerBookmarksShim::NodeRenamingMapKey::~NodeRenamingMapKey() {}
167
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_);
172 }
173
174 // static
175 void PartnerBookmarksShim::ClearInBrowserContextForTesting(
176     content::BrowserContext* browser_context) {
177   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
178   browser_context->SetUserData(kPartnerBookmarksShimUserDataKey, 0);
179 }
180
181 // static
182 void PartnerBookmarksShim::ClearPartnerModelForTesting() {
183   g_partner_model_keeper.Get().loaded = false;
184   g_partner_model_keeper.Get().partner_bookmarks_root.reset(0);
185 }
186
187 PartnerBookmarksShim::PartnerBookmarksShim(PrefService* prefs)
188     : prefs_(prefs),
189       observers_(
190           ObserverList<PartnerBookmarksShim::Observer>::NOTIFY_EXISTING_ONLY) {
191 }
192
193 PartnerBookmarksShim::~PartnerBookmarksShim() {
194   FOR_EACH_OBSERVER(PartnerBookmarksShim::Observer, observers_,
195                     ShimBeingDeleted(this));
196 }
197
198 const BookmarkNode* PartnerBookmarksShim::GetNodeByID(
199     const BookmarkNode* parent, int64 id) const {
200   if (parent->id() == id)
201     return parent;
202   for (int i = 0, child_count = parent->child_count(); i < child_count; ++i) {
203     const BookmarkNode* result = GetNodeByID(parent->GetChild(i), id);
204     if (result)
205       return result;
206   }
207   return NULL;
208 }
209
210 void PartnerBookmarksShim::ReloadNodeMapping() {
211   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
212
213   node_rename_remove_map_.clear();
214   if (!prefs_)
215     return;
216
217   const base::ListValue* list =
218       prefs_->GetList(prefs::kPartnerBookmarkMappings);
219   if (!list)
220     return;
221
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)) {
226       NOTREACHED();
227       continue;
228     }
229
230     std::string url;
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)) {
236       NOTREACHED();
237       continue;
238     }
239
240     const NodeRenamingMapKey key(GURL(url), provider_title);
241     node_rename_remove_map_[key] = mapped_title;
242   }
243 }
244
245 void PartnerBookmarksShim::SaveNodeMapping() {
246   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
247   if (!prefs_)
248     return;
249
250   base::ListValue list;
251   for (NodeRenamingMap::const_iterator i = node_rename_remove_map_.begin();
252        i != node_rename_remove_map_.end();
253        ++i) {
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);
258     list.Append(dict);
259   }
260   prefs_->Set(prefs::kPartnerBookmarkMappings, list);
261 }