Supervised user block interstitial: Fix font
[chromium-blink-merge.git] / components / enhanced_bookmarks / enhanced_bookmark_model.cc
blob77ee726ffc2a0cf1ee1eba0810377d4a12d5d4b8
1 // Copyright 2014 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 "components/enhanced_bookmarks/enhanced_bookmark_model.h"
7 #include <iomanip>
8 #include <sstream>
10 #include "base/base64.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/rand_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "components/bookmarks/browser/bookmark_model.h"
16 #include "components/bookmarks/browser/bookmark_node.h"
17 #include "components/enhanced_bookmarks/enhanced_bookmark_model_observer.h"
18 #include "components/enhanced_bookmarks/proto/metadata.pb.h"
19 #include "ui/base/models/tree_node_iterator.h"
20 #include "url/gurl.h"
22 namespace {
23 const char* kBookmarkBarId = "f_bookmarks_bar";
25 const char* kFlagsKey = "stars.flags";
26 const char* kIdKey = "stars.id";
27 const char* kImageDataKey = "stars.imageData";
28 const char* kNoteKey = "stars.note";
29 const char* kOldIdKey = "stars.oldId";
30 const char* kPageDataKey = "stars.pageData";
31 const char* kVersionKey = "stars.version";
33 const char* kBookmarkPrefix = "ebc_";
35 enum Flags {
36 // When set the server will attempt to fill in image and snippet information.
37 NEEDS_OFFLINE_PROCESSING = 0x1,
40 // Helper method for working with bookmark metainfo.
41 std::string DataForMetaInfoField(const BookmarkNode* node,
42 const std::string& field) {
43 std::string value;
44 if (!node->GetMetaInfo(field, &value))
45 return std::string();
47 std::string decoded;
48 if (!base::Base64Decode(value, &decoded))
49 return std::string();
51 return decoded;
54 // Helper method for working with ImageData_ImageInfo.
55 bool PopulateImageData(const image::collections::ImageData_ImageInfo& info,
56 GURL* out_url,
57 int* width,
58 int* height) {
59 if (!info.has_url() || !info.has_width() || !info.has_height())
60 return false;
62 GURL url(info.url());
63 if (!url.is_valid())
64 return false;
66 *out_url = url;
67 *width = info.width();
68 *height = info.height();
69 return true;
72 // Generate a random remote id, with a prefix that depends on whether the node
73 // is a folder or a bookmark.
74 std::string GenerateRemoteId() {
75 std::stringstream random_id;
76 random_id << kBookmarkPrefix;
78 // Generate 32 digit hex string random suffix.
79 random_id << std::hex << std::setfill('0') << std::setw(16);
80 random_id << base::RandUint64() << base::RandUint64();
81 return random_id.str();
83 } // namespace
85 namespace enhanced_bookmarks {
87 EnhancedBookmarkModel::EnhancedBookmarkModel(BookmarkModel* bookmark_model,
88 const std::string& version)
89 : bookmark_model_(bookmark_model),
90 loaded_(false),
91 version_(version),
92 weak_ptr_factory_(this) {
93 bookmark_model_->AddObserver(this);
94 bookmark_model_->AddNonClonedKey(kIdKey);
95 if (bookmark_model_->loaded()) {
96 InitializeIdMap();
97 loaded_ = true;
101 EnhancedBookmarkModel::~EnhancedBookmarkModel() {
102 Shutdown();
105 void EnhancedBookmarkModel::Shutdown() {
106 if (bookmark_model_) {
107 FOR_EACH_OBSERVER(EnhancedBookmarkModelObserver,
108 observers_,
109 EnhancedBookmarkModelShuttingDown());
110 weak_ptr_factory_.InvalidateWeakPtrs();
111 bookmark_model_->RemoveObserver(this);
112 bookmark_model_ = NULL;
116 void EnhancedBookmarkModel::AddObserver(
117 EnhancedBookmarkModelObserver* observer) {
118 observers_.AddObserver(observer);
121 void EnhancedBookmarkModel::RemoveObserver(
122 EnhancedBookmarkModelObserver* observer) {
123 observers_.RemoveObserver(observer);
126 // Moves |node| to |new_parent| and inserts it at the given |index|.
127 void EnhancedBookmarkModel::Move(const BookmarkNode* node,
128 const BookmarkNode* new_parent,
129 int index) {
130 bookmark_model_->Move(node, new_parent, index);
133 // Adds a new folder node at the specified position.
134 const BookmarkNode* EnhancedBookmarkModel::AddFolder(
135 const BookmarkNode* parent,
136 int index,
137 const base::string16& title) {
138 BookmarkNode::MetaInfoMap meta_info;
139 meta_info[kVersionKey] = GetVersionString();
140 return bookmark_model_->AddFolderWithMetaInfo(parent, index, title,
141 &meta_info);
144 // Adds a url at the specified position.
145 const BookmarkNode* EnhancedBookmarkModel::AddURL(
146 const BookmarkNode* parent,
147 int index,
148 const base::string16& title,
149 const GURL& url,
150 const base::Time& creation_time) {
151 BookmarkNode::MetaInfoMap meta_info;
152 meta_info[kIdKey] = GenerateRemoteId();
153 meta_info[kVersionKey] = GetVersionString();
154 return bookmark_model_->AddURLWithCreationTimeAndMetaInfo(
155 parent, index, title, url, creation_time, &meta_info);
158 std::string EnhancedBookmarkModel::GetRemoteId(const BookmarkNode* node) {
159 if (node == bookmark_model_->bookmark_bar_node())
160 return kBookmarkBarId;
162 std::string id;
163 if (!node->GetMetaInfo(kIdKey, &id))
164 return std::string();
165 return id;
168 const BookmarkNode* EnhancedBookmarkModel::BookmarkForRemoteId(
169 const std::string& remote_id) {
170 IdToNodeMap::iterator it = id_map_.find(remote_id);
171 if (it != id_map_.end())
172 return it->second;
173 return NULL;
176 void EnhancedBookmarkModel::SetDescription(const BookmarkNode* node,
177 const std::string& description) {
178 SetMetaInfo(node, kNoteKey, description);
181 std::string EnhancedBookmarkModel::GetDescription(const BookmarkNode* node) {
182 // First, look for a custom note set by the user.
183 std::string description;
184 if (node->GetMetaInfo(kNoteKey, &description) && !description.empty())
185 return description;
187 // If none are present, return the snippet.
188 return GetSnippet(node);
191 bool EnhancedBookmarkModel::SetOriginalImage(const BookmarkNode* node,
192 const GURL& url,
193 int width,
194 int height) {
195 DCHECK(node->is_url());
196 DCHECK(url.is_valid());
198 std::string decoded(DataForMetaInfoField(node, kImageDataKey));
199 image::collections::ImageData data;
201 // Try to populate the imageData with the existing data.
202 if (decoded != "") {
203 // If the parsing fails, something is wrong. Immediately fail.
204 bool result = data.ParseFromString(decoded);
205 if (!result)
206 return false;
209 scoped_ptr<image::collections::ImageData_ImageInfo> info(
210 new image::collections::ImageData_ImageInfo);
211 info->set_url(url.spec());
212 info->set_width(width);
213 info->set_height(height);
214 data.set_allocated_original_info(info.release());
216 std::string output;
217 bool result = data.SerializePartialToString(&output);
218 if (!result)
219 return false;
221 std::string encoded;
222 base::Base64Encode(output, &encoded);
223 SetMetaInfo(node, kImageDataKey, encoded);
224 return true;
227 bool EnhancedBookmarkModel::GetOriginalImage(const BookmarkNode* node,
228 GURL* url,
229 int* width,
230 int* height) {
231 std::string decoded(DataForMetaInfoField(node, kImageDataKey));
232 if (decoded == "")
233 return false;
235 image::collections::ImageData data;
236 bool result = data.ParseFromString(decoded);
237 if (!result)
238 return false;
240 if (!data.has_original_info())
241 return false;
243 return PopulateImageData(data.original_info(), url, width, height);
246 bool EnhancedBookmarkModel::GetThumbnailImage(const BookmarkNode* node,
247 GURL* url,
248 int* width,
249 int* height) {
250 std::string decoded(DataForMetaInfoField(node, kImageDataKey));
251 if (decoded == "")
252 return false;
254 image::collections::ImageData data;
255 bool result = data.ParseFromString(decoded);
256 if (!result)
257 return false;
259 if (!data.has_thumbnail_info())
260 return false;
262 return PopulateImageData(data.thumbnail_info(), url, width, height);
265 std::string EnhancedBookmarkModel::GetSnippet(const BookmarkNode* node) {
266 std::string decoded(DataForMetaInfoField(node, kPageDataKey));
267 if (decoded.empty())
268 return decoded;
270 image::collections::PageData data;
271 bool result = data.ParseFromString(decoded);
272 if (!result)
273 return std::string();
275 return data.snippet();
278 void EnhancedBookmarkModel::SetVersionSuffix(
279 const std::string& version_suffix) {
280 version_suffix_ = version_suffix;
283 void EnhancedBookmarkModel::BookmarkModelChanged() {
286 void EnhancedBookmarkModel::BookmarkModelLoaded(BookmarkModel* model,
287 bool ids_reassigned) {
288 InitializeIdMap();
289 loaded_ = true;
290 FOR_EACH_OBSERVER(
291 EnhancedBookmarkModelObserver, observers_, EnhancedBookmarkModelLoaded());
294 void EnhancedBookmarkModel::BookmarkNodeAdded(BookmarkModel* model,
295 const BookmarkNode* parent,
296 int index) {
297 const BookmarkNode* node = parent->GetChild(index);
298 std::string remote_id;
299 if (node->GetMetaInfo(kIdKey, &remote_id)) {
300 AddToIdMap(node);
301 ScheduleResetDuplicateRemoteIds();
302 } else if (node->is_url()) {
303 set_needs_offline_processing_tasks_[node] =
304 make_linked_ptr(new base::CancelableClosure(
305 base::Bind(&EnhancedBookmarkModel::SetNeedsOfflineProcessing,
306 weak_ptr_factory_.GetWeakPtr(),
307 base::Unretained(node))));
308 base::MessageLoopProxy::current()->PostTask(
309 FROM_HERE, set_needs_offline_processing_tasks_[node]->callback());
311 FOR_EACH_OBSERVER(
312 EnhancedBookmarkModelObserver, observers_, EnhancedBookmarkAdded(node));
315 void EnhancedBookmarkModel::BookmarkNodeRemoved(
316 BookmarkModel* model,
317 const BookmarkNode* parent,
318 int old_index,
319 const BookmarkNode* node,
320 const std::set<GURL>& removed_urls) {
321 RemoveNodeFromMaps(node);
322 FOR_EACH_OBSERVER(
323 EnhancedBookmarkModelObserver, observers_, EnhancedBookmarkRemoved(node));
326 void EnhancedBookmarkModel::BookmarkNodeChanged(BookmarkModel* model,
327 const BookmarkNode* node) {
328 FOR_EACH_OBSERVER(
329 EnhancedBookmarkModelObserver, observers_,
330 EnhancedBookmarkNodeChanged(node));
333 void EnhancedBookmarkModel::OnWillChangeBookmarkMetaInfo(
334 BookmarkModel* model,
335 const BookmarkNode* node) {
336 prev_remote_id_ = GetRemoteId(node);
339 void EnhancedBookmarkModel::BookmarkMetaInfoChanged(BookmarkModel* model,
340 const BookmarkNode* node) {
341 std::string remote_id = GetRemoteId(node);
342 if (remote_id != prev_remote_id_) {
343 id_map_.erase(prev_remote_id_);
344 if (!remote_id.empty()) {
345 AddToIdMap(node);
346 ScheduleResetDuplicateRemoteIds();
348 FOR_EACH_OBSERVER(
349 EnhancedBookmarkModelObserver,
350 observers_,
351 EnhancedBookmarkRemoteIdChanged(node, prev_remote_id_, remote_id));
355 void EnhancedBookmarkModel::BookmarkAllUserNodesRemoved(
356 BookmarkModel* model,
357 const std::set<GURL>& removed_urls) {
358 id_map_.clear();
359 // Re-initialize so non-user nodes with remote ids are present in the map.
360 InitializeIdMap();
361 FOR_EACH_OBSERVER(EnhancedBookmarkModelObserver,
362 observers_,
363 EnhancedBookmarkAllUserNodesRemoved());
366 void EnhancedBookmarkModel::InitializeIdMap() {
367 ui::TreeNodeIterator<const BookmarkNode> iterator(
368 bookmark_model_->root_node());
369 while (iterator.has_next()) {
370 AddToIdMap(iterator.Next());
372 ScheduleResetDuplicateRemoteIds();
375 void EnhancedBookmarkModel::AddToIdMap(const BookmarkNode* node) {
376 std::string remote_id = GetRemoteId(node);
377 if (remote_id.empty())
378 return;
380 // Try to insert the node.
381 std::pair<IdToNodeMap::iterator, bool> result =
382 id_map_.insert(make_pair(remote_id, node));
383 if (!result.second) {
384 // Some node already had the same remote id, so add both nodes to the
385 // to-be-reset set.
386 nodes_to_reset_[result.first->second] = remote_id;
387 nodes_to_reset_[node] = remote_id;
391 void EnhancedBookmarkModel::RemoveNodeFromMaps(const BookmarkNode* node) {
392 for (int i = 0; i < node->child_count(); i++) {
393 RemoveNodeFromMaps(node->GetChild(i));
395 std::string remote_id = GetRemoteId(node);
396 id_map_.erase(remote_id);
397 nodes_to_reset_.erase(node);
398 set_needs_offline_processing_tasks_.erase(node);
401 void EnhancedBookmarkModel::ScheduleResetDuplicateRemoteIds() {
402 if (!nodes_to_reset_.empty()) {
403 base::MessageLoopProxy::current()->PostTask(
404 FROM_HERE,
405 base::Bind(&EnhancedBookmarkModel::ResetDuplicateRemoteIds,
406 weak_ptr_factory_.GetWeakPtr()));
410 void EnhancedBookmarkModel::ResetDuplicateRemoteIds() {
411 for (NodeToIdMap::iterator it = nodes_to_reset_.begin();
412 it != nodes_to_reset_.end();
413 ++it) {
414 BookmarkNode::MetaInfoMap meta_info;
415 meta_info[kIdKey] = "";
416 meta_info[kOldIdKey] = it->second;
417 SetMultipleMetaInfo(it->first, meta_info);
419 nodes_to_reset_.clear();
422 void EnhancedBookmarkModel::SetNeedsOfflineProcessing(
423 const BookmarkNode* node) {
424 set_needs_offline_processing_tasks_.erase(node);
425 int flags = 0;
426 std::string flags_str;
427 if (node->GetMetaInfo(kFlagsKey, &flags_str)) {
428 if (!base::StringToInt(flags_str, &flags))
429 flags = 0;
431 flags |= NEEDS_OFFLINE_PROCESSING;
432 SetMetaInfo(node, kFlagsKey, base::IntToString(flags));
435 void EnhancedBookmarkModel::SetMetaInfo(const BookmarkNode* node,
436 const std::string& field,
437 const std::string& value) {
438 DCHECK(!bookmark_model_->is_permanent_node(node));
440 BookmarkNode::MetaInfoMap meta_info;
441 const BookmarkNode::MetaInfoMap* old_meta_info = node->GetMetaInfoMap();
442 if (old_meta_info)
443 meta_info.insert(old_meta_info->begin(), old_meta_info->end());
445 // Don't update anything if the value to set is already there.
446 BookmarkNode::MetaInfoMap::iterator it = meta_info.find(field);
447 if (it != meta_info.end() && it->second == value)
448 return;
450 meta_info[field] = value;
451 meta_info[kVersionKey] = GetVersionString();
452 bookmark_model_->SetNodeMetaInfoMap(node, meta_info);
455 std::string EnhancedBookmarkModel::GetVersionString() {
456 if (version_suffix_.empty())
457 return version_;
458 return version_ + '/' + version_suffix_;
461 void EnhancedBookmarkModel::SetMultipleMetaInfo(
462 const BookmarkNode* node,
463 BookmarkNode::MetaInfoMap meta_info) {
464 DCHECK(!bookmark_model_->is_permanent_node(node));
466 // Don't update anything if every value is already set correctly.
467 if (node->GetMetaInfoMap()) {
468 bool changed = false;
469 const BookmarkNode::MetaInfoMap* old_meta_info = node->GetMetaInfoMap();
470 for (BookmarkNode::MetaInfoMap::iterator it = meta_info.begin();
471 it != meta_info.end();
472 ++it) {
473 BookmarkNode::MetaInfoMap::const_iterator old_field =
474 old_meta_info->find(it->first);
475 if (old_field == old_meta_info->end() ||
476 old_field->second != it->second) {
477 changed = true;
478 break;
481 if (!changed)
482 return;
484 // Fill in the values that aren't changing
485 meta_info.insert(old_meta_info->begin(), old_meta_info->end());
488 meta_info[kVersionKey] = GetVersionString();
489 bookmark_model_->SetNodeMetaInfoMap(node, meta_info);
492 bool EnhancedBookmarkModel::SetAllImages(const BookmarkNode* node,
493 const GURL& image_url,
494 int image_width,
495 int image_height,
496 const GURL& thumbnail_url,
497 int thumbnail_width,
498 int thumbnail_height) {
499 DCHECK(node->is_url());
500 DCHECK(image_url.is_valid() || image_url.is_empty());
501 DCHECK(thumbnail_url.is_valid() || thumbnail_url.is_empty());
502 std::string decoded(DataForMetaInfoField(node, kImageDataKey));
503 image::collections::ImageData data;
505 // Try to populate the imageData with the existing data.
506 if (decoded != "") {
507 // If the parsing fails, something is wrong. Immediately fail.
508 bool result = data.ParseFromString(decoded);
509 if (!result)
510 return false;
513 if (image_url.is_empty()) {
514 data.release_original_info();
515 } else {
516 // Regardless of whether an image info exists, we make a new one.
517 // Intentially make a raw pointer.
518 image::collections::ImageData_ImageInfo* info =
519 new image::collections::ImageData_ImageInfo;
520 info->set_url(image_url.spec());
521 info->set_width(image_width);
522 info->set_height(image_height);
523 // This method consumes the raw pointer.
524 data.set_allocated_original_info(info);
527 if (thumbnail_url.is_empty()) {
528 data.release_thumbnail_info();
529 } else {
530 // Regardless of whether an image info exists, we make a new one.
531 // Intentially make a raw pointer.
532 image::collections::ImageData_ImageInfo* info =
533 new image::collections::ImageData_ImageInfo;
534 info->set_url(thumbnail_url.spec());
535 info->set_width(thumbnail_width);
536 info->set_height(thumbnail_height);
537 // This method consumes the raw pointer.
538 data.set_allocated_thumbnail_info(info);
540 std::string output;
541 bool result = data.SerializePartialToString(&output);
542 if (!result)
543 return false;
545 std::string encoded;
546 base::Base64Encode(output, &encoded);
547 bookmark_model_->SetNodeMetaInfo(node, kImageDataKey, encoded);
548 return true;
551 } // namespace enhanced_bookmarks