Android Chromoting: Remove exit-fullscreen button.
[chromium-blink-merge.git] / components / enhanced_bookmarks / enhanced_bookmark_model.cc
blob42bb5cec1df2a6f56d0b689d7d2bac1c7cb4b89d
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 using bookmarks::BookmarkModel;
23 using bookmarks::BookmarkNode;
25 namespace {
26 const char* kBookmarkBarId = "f_bookmarks_bar";
28 const char* kIdKey = "stars.id";
29 const char* kImageDataKey = "stars.imageData";
30 const char* kNoteKey = "stars.note";
31 const char* kOldIdKey = "stars.oldId";
32 const char* kPageDataKey = "stars.pageData";
33 const char* kVersionKey = "stars.version";
35 const char* kBookmarkPrefix = "ebc_";
37 // Helper method for working with bookmark metainfo.
38 std::string DataForMetaInfoField(const BookmarkNode* node,
39 const std::string& field) {
40 std::string value;
41 if (!node->GetMetaInfo(field, &value))
42 return std::string();
44 std::string decoded;
45 if (!base::Base64Decode(value, &decoded))
46 return std::string();
48 return decoded;
51 // Helper method for working with ImageData_ImageInfo.
52 bool PopulateImageData(const image::collections::ImageData_ImageInfo& info,
53 GURL* out_url,
54 int* width,
55 int* height) {
56 if (!info.has_url() || !info.has_width() || !info.has_height())
57 return false;
59 GURL url(info.url());
60 if (!url.is_valid())
61 return false;
63 *out_url = url;
64 *width = info.width();
65 *height = info.height();
66 return true;
69 // Generate a random remote id, with a prefix that depends on whether the node
70 // is a folder or a bookmark.
71 std::string GenerateRemoteId() {
72 std::stringstream random_id;
73 random_id << kBookmarkPrefix;
75 // Generate 32 digit hex string random suffix.
76 random_id << std::hex << std::setfill('0') << std::setw(16);
77 random_id << base::RandUint64() << base::RandUint64();
78 return random_id.str();
80 } // namespace
82 namespace enhanced_bookmarks {
84 EnhancedBookmarkModel::EnhancedBookmarkModel(BookmarkModel* bookmark_model,
85 const std::string& version)
86 : bookmark_model_(bookmark_model),
87 loaded_(false),
88 version_(version),
89 weak_ptr_factory_(this) {
90 bookmark_model_->AddObserver(this);
91 bookmark_model_->AddNonClonedKey(kIdKey);
92 if (bookmark_model_->loaded()) {
93 InitializeIdMap();
94 loaded_ = true;
98 EnhancedBookmarkModel::~EnhancedBookmarkModel() {
99 Shutdown();
102 void EnhancedBookmarkModel::Shutdown() {
103 if (bookmark_model_) {
104 FOR_EACH_OBSERVER(EnhancedBookmarkModelObserver,
105 observers_,
106 EnhancedBookmarkModelShuttingDown());
107 weak_ptr_factory_.InvalidateWeakPtrs();
108 bookmark_model_->RemoveObserver(this);
109 bookmark_model_ = NULL;
113 void EnhancedBookmarkModel::AddObserver(
114 EnhancedBookmarkModelObserver* observer) {
115 observers_.AddObserver(observer);
118 void EnhancedBookmarkModel::RemoveObserver(
119 EnhancedBookmarkModelObserver* observer) {
120 observers_.RemoveObserver(observer);
123 // Moves |node| to |new_parent| and inserts it at the given |index|.
124 void EnhancedBookmarkModel::Move(const BookmarkNode* node,
125 const BookmarkNode* new_parent,
126 int index) {
127 bookmark_model_->Move(node, new_parent, index);
130 // Adds a new folder node at the specified position.
131 const BookmarkNode* EnhancedBookmarkModel::AddFolder(
132 const BookmarkNode* parent,
133 int index,
134 const base::string16& title) {
135 BookmarkNode::MetaInfoMap meta_info;
136 meta_info[kVersionKey] = GetVersionString();
137 return bookmark_model_->AddFolderWithMetaInfo(parent, index, title,
138 &meta_info);
141 // Adds a url at the specified position.
142 const BookmarkNode* EnhancedBookmarkModel::AddURL(
143 const BookmarkNode* parent,
144 int index,
145 const base::string16& title,
146 const GURL& url,
147 const base::Time& creation_time) {
148 BookmarkNode::MetaInfoMap meta_info;
149 meta_info[kIdKey] = GenerateRemoteId();
150 meta_info[kVersionKey] = GetVersionString();
151 return bookmark_model_->AddURLWithCreationTimeAndMetaInfo(
152 parent, index, title, url, creation_time, &meta_info);
155 std::string EnhancedBookmarkModel::GetRemoteId(const BookmarkNode* node) {
156 if (node == bookmark_model_->bookmark_bar_node())
157 return kBookmarkBarId;
159 std::string id;
160 if (!node->GetMetaInfo(kIdKey, &id))
161 return std::string();
162 return id;
165 const BookmarkNode* EnhancedBookmarkModel::BookmarkForRemoteId(
166 const std::string& remote_id) {
167 IdToNodeMap::iterator it = id_map_.find(remote_id);
168 if (it != id_map_.end())
169 return it->second;
170 return NULL;
173 void EnhancedBookmarkModel::SetDescription(const BookmarkNode* node,
174 const std::string& description) {
175 SetMetaInfo(node, kNoteKey, description);
178 std::string EnhancedBookmarkModel::GetDescription(const BookmarkNode* node) {
179 // First, look for a custom note set by the user.
180 std::string description;
181 if (node->GetMetaInfo(kNoteKey, &description) && !description.empty())
182 return description;
184 // If none are present, return the snippet.
185 return GetSnippet(node);
188 bool EnhancedBookmarkModel::SetOriginalImage(const BookmarkNode* node,
189 const GURL& url,
190 int width,
191 int height) {
192 DCHECK(node->is_url());
193 DCHECK(url.is_valid());
195 std::string decoded(DataForMetaInfoField(node, kImageDataKey));
196 image::collections::ImageData data;
198 // Try to populate the imageData with the existing data.
199 if (!decoded.empty()) {
200 // If the parsing fails, something is wrong. Immediately fail.
201 bool result = data.ParseFromString(decoded);
202 if (!result)
203 return false;
206 scoped_ptr<image::collections::ImageData_ImageInfo> info(
207 new image::collections::ImageData_ImageInfo);
208 info->set_url(url.spec());
209 info->set_width(width);
210 info->set_height(height);
211 data.set_allocated_original_info(info.release());
213 std::string output;
214 bool result = data.SerializePartialToString(&output);
215 if (!result)
216 return false;
218 std::string encoded;
219 base::Base64Encode(output, &encoded);
220 SetMetaInfo(node, kImageDataKey, encoded);
221 return true;
224 void EnhancedBookmarkModel::RemoveImageData(const BookmarkNode* node) {
225 DCHECK(node->is_url());
226 image::collections::ImageData data;
227 data.set_user_removed_image(true);
229 std::string encoded_data;
230 base::Base64Encode(data.SerializeAsString(), &encoded_data);
231 SetMetaInfo(node, kImageDataKey, encoded_data);
234 bool EnhancedBookmarkModel::GetOriginalImage(const BookmarkNode* node,
235 GURL* url,
236 int* width,
237 int* height) {
238 std::string decoded(DataForMetaInfoField(node, kImageDataKey));
239 if (decoded.empty())
240 return false;
242 image::collections::ImageData data;
243 bool result = data.ParseFromString(decoded);
244 if (!result)
245 return false;
247 if (!data.has_original_info())
248 return false;
250 return PopulateImageData(data.original_info(), url, width, height);
253 bool EnhancedBookmarkModel::GetThumbnailImage(const BookmarkNode* node,
254 GURL* url,
255 int* width,
256 int* height) {
257 std::string decoded(DataForMetaInfoField(node, kImageDataKey));
258 if (decoded.empty())
259 return false;
261 image::collections::ImageData data;
262 bool result = data.ParseFromString(decoded);
263 if (!result)
264 return false;
266 if (!data.has_thumbnail_info())
267 return false;
269 return PopulateImageData(data.thumbnail_info(), url, width, height);
272 std::string EnhancedBookmarkModel::GetSnippet(const BookmarkNode* node) {
273 std::string decoded(DataForMetaInfoField(node, kPageDataKey));
274 if (decoded.empty())
275 return decoded;
277 image::collections::PageData data;
278 bool result = data.ParseFromString(decoded);
279 if (!result)
280 return std::string();
282 return data.snippet();
285 void EnhancedBookmarkModel::SetVersionSuffix(
286 const std::string& version_suffix) {
287 version_suffix_ = version_suffix;
290 void EnhancedBookmarkModel::BookmarkModelChanged() {
293 void EnhancedBookmarkModel::BookmarkModelLoaded(BookmarkModel* model,
294 bool ids_reassigned) {
295 InitializeIdMap();
296 loaded_ = true;
297 FOR_EACH_OBSERVER(
298 EnhancedBookmarkModelObserver, observers_, EnhancedBookmarkModelLoaded());
301 void EnhancedBookmarkModel::BookmarkNodeAdded(BookmarkModel* model,
302 const BookmarkNode* parent,
303 int index) {
304 const BookmarkNode* node = parent->GetChild(index);
305 std::string remote_id;
306 if (node->GetMetaInfo(kIdKey, &remote_id)) {
307 AddToIdMap(node);
308 ScheduleResetDuplicateRemoteIds();
310 FOR_EACH_OBSERVER(
311 EnhancedBookmarkModelObserver, observers_, EnhancedBookmarkAdded(node));
314 void EnhancedBookmarkModel::BookmarkNodeRemoved(
315 BookmarkModel* model,
316 const BookmarkNode* parent,
317 int old_index,
318 const BookmarkNode* node,
319 const std::set<GURL>& removed_urls) {
320 RemoveNodeFromMaps(node);
321 FOR_EACH_OBSERVER(
322 EnhancedBookmarkModelObserver, observers_, EnhancedBookmarkRemoved(node));
325 void EnhancedBookmarkModel::BookmarkNodeChanged(BookmarkModel* model,
326 const BookmarkNode* node) {
327 FOR_EACH_OBSERVER(
328 EnhancedBookmarkModelObserver, observers_,
329 EnhancedBookmarkNodeChanged(node));
332 void EnhancedBookmarkModel::OnWillChangeBookmarkMetaInfo(
333 BookmarkModel* model,
334 const BookmarkNode* node) {
335 prev_remote_id_ = GetRemoteId(node);
338 void EnhancedBookmarkModel::BookmarkMetaInfoChanged(BookmarkModel* model,
339 const BookmarkNode* node) {
340 std::string remote_id = GetRemoteId(node);
341 if (remote_id != prev_remote_id_) {
342 id_map_.erase(prev_remote_id_);
343 if (!remote_id.empty()) {
344 AddToIdMap(node);
345 ScheduleResetDuplicateRemoteIds();
347 FOR_EACH_OBSERVER(
348 EnhancedBookmarkModelObserver,
349 observers_,
350 EnhancedBookmarkRemoteIdChanged(node, prev_remote_id_, remote_id));
354 void EnhancedBookmarkModel::BookmarkAllUserNodesRemoved(
355 BookmarkModel* model,
356 const std::set<GURL>& removed_urls) {
357 id_map_.clear();
358 // Re-initialize so non-user nodes with remote ids are present in the map.
359 InitializeIdMap();
360 FOR_EACH_OBSERVER(EnhancedBookmarkModelObserver,
361 observers_,
362 EnhancedBookmarkAllUserNodesRemoved());
365 void EnhancedBookmarkModel::InitializeIdMap() {
366 ui::TreeNodeIterator<const BookmarkNode> iterator(
367 bookmark_model_->root_node());
368 while (iterator.has_next()) {
369 AddToIdMap(iterator.Next());
371 ScheduleResetDuplicateRemoteIds();
374 void EnhancedBookmarkModel::AddToIdMap(const BookmarkNode* node) {
375 std::string remote_id = GetRemoteId(node);
376 if (remote_id.empty())
377 return;
379 // Try to insert the node.
380 std::pair<IdToNodeMap::iterator, bool> result =
381 id_map_.insert(make_pair(remote_id, node));
382 if (!result.second) {
383 // Some node already had the same remote id, so add both nodes to the
384 // to-be-reset set.
385 nodes_to_reset_[result.first->second] = remote_id;
386 nodes_to_reset_[node] = remote_id;
390 void EnhancedBookmarkModel::RemoveNodeFromMaps(const BookmarkNode* node) {
391 for (int i = 0; i < node->child_count(); i++) {
392 RemoveNodeFromMaps(node->GetChild(i));
394 std::string remote_id = GetRemoteId(node);
395 id_map_.erase(remote_id);
396 nodes_to_reset_.erase(node);
399 void EnhancedBookmarkModel::ScheduleResetDuplicateRemoteIds() {
400 if (!nodes_to_reset_.empty()) {
401 base::MessageLoopProxy::current()->PostTask(
402 FROM_HERE,
403 base::Bind(&EnhancedBookmarkModel::ResetDuplicateRemoteIds,
404 weak_ptr_factory_.GetWeakPtr()));
408 void EnhancedBookmarkModel::ResetDuplicateRemoteIds() {
409 for (NodeToIdMap::iterator it = nodes_to_reset_.begin();
410 it != nodes_to_reset_.end();
411 ++it) {
412 BookmarkNode::MetaInfoMap meta_info;
413 meta_info[kIdKey] = "";
414 meta_info[kOldIdKey] = it->second;
415 SetMultipleMetaInfo(it->first, meta_info);
417 nodes_to_reset_.clear();
420 void EnhancedBookmarkModel::SetMetaInfo(const BookmarkNode* node,
421 const std::string& field,
422 const std::string& value) {
423 DCHECK(!bookmark_model_->is_permanent_node(node));
425 BookmarkNode::MetaInfoMap meta_info;
426 const BookmarkNode::MetaInfoMap* old_meta_info = node->GetMetaInfoMap();
427 if (old_meta_info)
428 meta_info.insert(old_meta_info->begin(), old_meta_info->end());
430 // Don't update anything if the value to set is already there.
431 BookmarkNode::MetaInfoMap::iterator it = meta_info.find(field);
432 if (it != meta_info.end() && it->second == value)
433 return;
435 meta_info[field] = value;
436 meta_info[kVersionKey] = GetVersionString();
437 bookmark_model_->SetNodeMetaInfoMap(node, meta_info);
440 std::string EnhancedBookmarkModel::GetVersionString() {
441 if (version_suffix_.empty())
442 return version_;
443 return version_ + '/' + version_suffix_;
446 void EnhancedBookmarkModel::SetMultipleMetaInfo(
447 const BookmarkNode* node,
448 BookmarkNode::MetaInfoMap meta_info) {
449 DCHECK(!bookmark_model_->is_permanent_node(node));
451 // Don't update anything if every value is already set correctly.
452 if (node->GetMetaInfoMap()) {
453 bool changed = false;
454 const BookmarkNode::MetaInfoMap* old_meta_info = node->GetMetaInfoMap();
455 for (BookmarkNode::MetaInfoMap::iterator it = meta_info.begin();
456 it != meta_info.end();
457 ++it) {
458 BookmarkNode::MetaInfoMap::const_iterator old_field =
459 old_meta_info->find(it->first);
460 if (old_field == old_meta_info->end() ||
461 old_field->second != it->second) {
462 changed = true;
463 break;
466 if (!changed)
467 return;
469 // Fill in the values that aren't changing
470 meta_info.insert(old_meta_info->begin(), old_meta_info->end());
473 meta_info[kVersionKey] = GetVersionString();
474 bookmark_model_->SetNodeMetaInfoMap(node, meta_info);
477 bool EnhancedBookmarkModel::SetAllImages(const BookmarkNode* node,
478 const GURL& image_url,
479 int image_width,
480 int image_height,
481 const GURL& thumbnail_url,
482 int thumbnail_width,
483 int thumbnail_height) {
484 DCHECK(node->is_url());
485 DCHECK(image_url.is_valid() || image_url.is_empty());
486 DCHECK(thumbnail_url.is_valid() || thumbnail_url.is_empty());
487 std::string decoded(DataForMetaInfoField(node, kImageDataKey));
488 image::collections::ImageData data;
490 // Try to populate the imageData with the existing data.
491 if (!decoded.empty()) {
492 // If the parsing fails, something is wrong. Immediately fail.
493 bool result = data.ParseFromString(decoded);
494 if (!result)
495 return false;
498 if (image_url.is_empty()) {
499 data.release_original_info();
500 } else {
501 // Regardless of whether an image info exists, we make a new one.
502 // Intentially make a raw pointer.
503 image::collections::ImageData_ImageInfo* info =
504 new image::collections::ImageData_ImageInfo;
505 info->set_url(image_url.spec());
506 info->set_width(image_width);
507 info->set_height(image_height);
508 // This method consumes the raw pointer.
509 data.set_allocated_original_info(info);
512 if (thumbnail_url.is_empty()) {
513 data.release_thumbnail_info();
514 } else {
515 // Regardless of whether an image info exists, we make a new one.
516 // Intentially make a raw pointer.
517 image::collections::ImageData_ImageInfo* info =
518 new image::collections::ImageData_ImageInfo;
519 info->set_url(thumbnail_url.spec());
520 info->set_width(thumbnail_width);
521 info->set_height(thumbnail_height);
522 // This method consumes the raw pointer.
523 data.set_allocated_thumbnail_info(info);
525 std::string output;
526 bool result = data.SerializePartialToString(&output);
527 if (!result)
528 return false;
530 std::string encoded;
531 base::Base64Encode(output, &encoded);
532 bookmark_model_->SetNodeMetaInfo(node, kImageDataKey, encoded);
533 return true;
536 } // namespace enhanced_bookmarks