blob: 766726339e312ffc5531910573b3e32cafbe159d [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/bookmarks/browser/bookmark_node.h"
#include <map>
#include <memory>
#include <string>
#include "base/check.h"
#include "base/check_op.h"
#include "base/guid.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace bookmarks {
namespace {
// Whitespace characters to strip from bookmark titles.
const char16_t kInvalidChars[] = {'\n', '\r', '\t',
0x2028, // Line separator
0x2029, // Paragraph separator
0};
} // namespace
// BookmarkNode ---------------------------------------------------------------
// Below predefined GUIDs for permanent bookmark folders, determined via named
// GUIDs/UUIDs. Do NOT modify them as they may be exposed via Sync. For
// reference, here's the python script to produce them:
// > import uuid
// > chromium_namespace = uuid.uuid5(uuid.NAMESPACE_DNS, "chromium.org")
// > bookmarks_namespace = uuid.uuid5(chromium_namespace, "bookmarks")
// > root_guid = uuid.uuid5(bookmarks_namespace, "root")
// > bookmark_bar = uuid.uuid5(bookmarks_namespace, "bookmark_bar")
// > mobile_bookmarks = uuid.uuid5(bookmarks_namespace, "mobile_bookmarks")
// > other_bookmarks = uuid.uuid5(bookmarks_namespace, "other_bookmarks")
// > managed_bookmarks = uuid.uuid5(bookmarks_namespace, "managed_bookmarks")
// static
const char BookmarkNode::kRootNodeGuid[] =
"2509a7dc-215d-52f7-a429-8d80431c6c75";
// static
const char BookmarkNode::kBookmarkBarNodeGuid[] =
"0bc5d13f-2cba-5d74-951f-3f233fe6c908";
// static
const char BookmarkNode::kOtherBookmarksNodeGuid[] =
"82b081ec-3dd3-529c-8475-ab6c344590dd";
// static
const char BookmarkNode::kMobileBookmarksNodeGuid[] =
"4cf2e351-0e85-532b-bb37-df045d8f8d0f";
// static
const char BookmarkNode::kManagedNodeGuid[] =
"323123f4-9381-5aee-80e6-ea5fca2f7672";
BookmarkNode::BookmarkNode(int64_t id, const base::GUID& guid, const GURL& url)
: BookmarkNode(id, guid, url, url.is_empty() ? FOLDER : URL, false) {}
BookmarkNode::~BookmarkNode() = default;
void BookmarkNode::SetTitle(const std::u16string& title) {
// Replace newlines and other problematic whitespace characters in
// folder/bookmark names with spaces.
std::u16string trimmed_title;
base::ReplaceChars(title, kInvalidChars, u" ", &trimmed_title);
ui::TreeNode<BookmarkNode>::SetTitle(trimmed_title);
}
bool BookmarkNode::IsVisible() const {
return true;
}
bool BookmarkNode::GetMetaInfo(const std::string& key,
std::string* value) const {
if (!meta_info_map_)
return false;
MetaInfoMap::const_iterator it = meta_info_map_->find(key);
if (it == meta_info_map_->end())
return false;
*value = it->second;
return true;
}
bool BookmarkNode::SetMetaInfo(const std::string& key,
const std::string& value) {
if (!meta_info_map_)
meta_info_map_ = std::make_unique<MetaInfoMap>();
auto it = meta_info_map_->find(key);
if (it == meta_info_map_->end()) {
(*meta_info_map_)[key] = value;
return true;
}
// Key already in map, check if the value has changed.
if (it->second == value)
return false;
it->second = value;
return true;
}
bool BookmarkNode::DeleteMetaInfo(const std::string& key) {
if (!meta_info_map_)
return false;
bool erased = meta_info_map_->erase(key) != 0;
if (meta_info_map_->empty())
meta_info_map_.reset();
return erased;
}
void BookmarkNode::SetMetaInfoMap(const MetaInfoMap& meta_info_map) {
if (meta_info_map.empty())
meta_info_map_.reset();
else
meta_info_map_ = std::make_unique<MetaInfoMap>(meta_info_map);
}
const BookmarkNode::MetaInfoMap* BookmarkNode::GetMetaInfoMap() const {
return meta_info_map_.get();
}
const std::u16string& BookmarkNode::GetTitledUrlNodeTitle() const {
return GetTitle();
}
const GURL& BookmarkNode::GetTitledUrlNodeUrl() const {
return url_;
}
std::vector<base::StringPiece16> BookmarkNode::GetTitledUrlNodeAncestorTitles()
const {
std::vector<base::StringPiece16> paths;
for (const BookmarkNode* n = this; n->parent(); n = n->parent())
paths.push_back(n->parent()->GetTitle());
return paths;
}
BookmarkNode::BookmarkNode(int64_t id,
const base::GUID& guid,
const GURL& url,
Type type,
bool is_permanent_node)
: id_(id),
guid_(guid),
url_(url),
type_(type),
date_added_(base::Time::Now()),
is_permanent_node_(is_permanent_node) {
DCHECK_NE(type == URL, url.is_empty());
DCHECK(guid.is_valid());
}
void BookmarkNode::InvalidateFavicon() {
icon_url_.reset();
favicon_ = gfx::Image();
favicon_state_ = INVALID_FAVICON;
}
// BookmarkPermanentNode -------------------------------------------------------
// static
std::unique_ptr<BookmarkPermanentNode>
BookmarkPermanentNode::CreateManagedBookmarks(int64_t id) {
// base::WrapUnique() used because the constructor is private.
return base::WrapUnique(new BookmarkPermanentNode(
id, FOLDER, base::GUID::ParseLowercase(kManagedNodeGuid),
std::u16string(),
/*visible_when_empty=*/false));
}
BookmarkPermanentNode::~BookmarkPermanentNode() = default;
bool BookmarkPermanentNode::IsVisible() const {
return visible_when_empty_ || !children().empty();
}
// static
std::unique_ptr<BookmarkPermanentNode> BookmarkPermanentNode::CreateBookmarkBar(
int64_t id,
bool visible_when_empty) {
// base::WrapUnique() used because the constructor is private.
return base::WrapUnique(new BookmarkPermanentNode(
id, BOOKMARK_BAR, base::GUID::ParseLowercase(kBookmarkBarNodeGuid),
l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_FOLDER_NAME),
visible_when_empty));
}
// static
std::unique_ptr<BookmarkPermanentNode>
BookmarkPermanentNode::CreateOtherBookmarks(int64_t id,
bool visible_when_empty) {
// base::WrapUnique() used because the constructor is private.
return base::WrapUnique(new BookmarkPermanentNode(
id, OTHER_NODE, base::GUID::ParseLowercase(kOtherBookmarksNodeGuid),
l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME),
visible_when_empty));
}
// static
std::unique_ptr<BookmarkPermanentNode>
BookmarkPermanentNode::CreateMobileBookmarks(int64_t id,
bool visible_when_empty) {
// base::WrapUnique() used because the constructor is private.
return base::WrapUnique(new BookmarkPermanentNode(
id, MOBILE, base::GUID::ParseLowercase(kMobileBookmarksNodeGuid),
l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME),
visible_when_empty));
}
BookmarkPermanentNode::BookmarkPermanentNode(int64_t id,
Type type,
const base::GUID& guid,
const std::u16string& title,
bool visible_when_empty)
: BookmarkNode(id, guid, GURL(), type, /*is_permanent_node=*/true),
visible_when_empty_(visible_when_empty) {
DCHECK(type != URL);
SetTitle(title);
}
} // namespace bookmarks