Popular sites on the NTP: Try to keep the ordering constant
[chromium-blink-merge.git] / components / bookmarks / browser / bookmark_node_data.cc
blobda1d6754d633001f22e61803277640f301e1ec12
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/bookmarks/browser/bookmark_node_data.h"
7 #include <string>
9 #include "base/pickle.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/bookmarks/browser/bookmark_utils.h"
13 #include "ui/base/clipboard/scoped_clipboard_writer.h"
15 namespace bookmarks {
17 const char* BookmarkNodeData::kClipboardFormatString =
18 "chromium/x-bookmark-entries";
20 BookmarkNodeData::Element::Element() : is_url(false), id_(0) {
23 BookmarkNodeData::Element::Element(const BookmarkNode* node)
24 : is_url(node->is_url()),
25 url(node->url()),
26 title(node->GetTitle()),
27 date_added(node->date_added()),
28 date_folder_modified(node->date_folder_modified()),
29 id_(node->id()) {
30 if (node->GetMetaInfoMap())
31 meta_info_map = *node->GetMetaInfoMap();
32 for (int i = 0; i < node->child_count(); ++i)
33 children.push_back(Element(node->GetChild(i)));
36 BookmarkNodeData::Element::~Element() {
39 void BookmarkNodeData::Element::WriteToPickle(base::Pickle* pickle) const {
40 pickle->WriteBool(is_url);
41 pickle->WriteString(url.spec());
42 pickle->WriteString16(title);
43 pickle->WriteInt64(id_);
44 pickle->WriteSizeT(meta_info_map.size());
45 for (BookmarkNode::MetaInfoMap::const_iterator it = meta_info_map.begin();
46 it != meta_info_map.end(); ++it) {
47 pickle->WriteString(it->first);
48 pickle->WriteString(it->second);
50 if (!is_url) {
51 pickle->WriteSizeT(children.size());
52 for (std::vector<Element>::const_iterator i = children.begin();
53 i != children.end(); ++i) {
54 i->WriteToPickle(pickle);
59 bool BookmarkNodeData::Element::ReadFromPickle(base::PickleIterator* iterator) {
60 std::string url_spec;
61 if (!iterator->ReadBool(&is_url) ||
62 !iterator->ReadString(&url_spec) ||
63 !iterator->ReadString16(&title) ||
64 !iterator->ReadInt64(&id_)) {
65 return false;
67 url = GURL(url_spec);
68 date_added = base::Time();
69 date_folder_modified = base::Time();
70 meta_info_map.clear();
71 size_t meta_field_count;
72 if (!iterator->ReadSizeT(&meta_field_count))
73 return false;
74 for (size_t i = 0; i < meta_field_count; ++i) {
75 std::string key;
76 std::string value;
77 if (!iterator->ReadString(&key) ||
78 !iterator->ReadString(&value)) {
79 return false;
81 meta_info_map[key] = value;
83 children.clear();
84 if (!is_url) {
85 size_t children_count;
86 if (!iterator->ReadSizeT(&children_count))
87 return false;
88 children.reserve(children_count);
89 for (size_t i = 0; i < children_count; ++i) {
90 children.push_back(Element());
91 if (!children.back().ReadFromPickle(iterator))
92 return false;
95 return true;
98 // BookmarkNodeData -----------------------------------------------------------
100 BookmarkNodeData::BookmarkNodeData() {
103 BookmarkNodeData::BookmarkNodeData(const BookmarkNode* node) {
104 elements.push_back(Element(node));
107 BookmarkNodeData::BookmarkNodeData(
108 const std::vector<const BookmarkNode*>& nodes) {
109 ReadFromVector(nodes);
112 BookmarkNodeData::~BookmarkNodeData() {
115 #if !defined(OS_MACOSX)
116 // static
117 bool BookmarkNodeData::ClipboardContainsBookmarks() {
118 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
119 ui::Clipboard::GetFormatType(kClipboardFormatString),
120 ui::CLIPBOARD_TYPE_COPY_PASTE);
122 #endif
124 bool BookmarkNodeData::ReadFromVector(
125 const std::vector<const BookmarkNode*>& nodes) {
126 Clear();
128 if (nodes.empty())
129 return false;
131 for (size_t i = 0; i < nodes.size(); ++i)
132 elements.push_back(Element(nodes[i]));
134 return true;
137 bool BookmarkNodeData::ReadFromTuple(const GURL& url,
138 const base::string16& title) {
139 Clear();
141 if (!url.is_valid())
142 return false;
144 Element element;
145 element.title = title;
146 element.url = url;
147 element.is_url = true;
149 elements.push_back(element);
151 return true;
154 #if !defined(OS_MACOSX)
155 void BookmarkNodeData::WriteToClipboard(ui::ClipboardType clipboard_type) {
156 DCHECK(clipboard_type == ui::CLIPBOARD_TYPE_COPY_PASTE ||
157 clipboard_type == ui::CLIPBOARD_TYPE_SELECTION);
158 ui::ScopedClipboardWriter scw(clipboard_type);
160 // If there is only one element and it is a URL, write the URL to the
161 // clipboard.
162 if (has_single_url()) {
163 const base::string16& title = elements[0].title;
164 const std::string url = elements[0].url.spec();
166 scw.WriteBookmark(title, url);
168 // Don't call scw.WriteHyperlink() here, since some rich text editors will
169 // change fonts when such data is pasted in; besides, most such editors
170 // auto-linkify at some point anyway.
172 // Also write the URL to the clipboard as text so that it can be pasted
173 // into text fields. We use WriteText instead of WriteURL because we don't
174 // want to clobber the X clipboard when the user copies out of the omnibox
175 // on Linux (on Windows and Mac, there is no difference between these
176 // functions).
177 scw.WriteText(base::UTF8ToUTF16(url));
178 } else {
179 // We have either more than one URL, a folder, or a combination of URLs
180 // and folders.
181 base::string16 text;
182 for (size_t i = 0; i < size(); i++) {
183 text += i == 0 ? base::ASCIIToUTF16("") : base::ASCIIToUTF16("\n");
184 if (!elements[i].is_url) {
185 // Then it's a folder. Only copy the name of the folder.
186 const base::string16 title = elements[i].title;
187 text += title;
188 } else {
189 const base::string16 url = base::UTF8ToUTF16(elements[i].url.spec());
190 text += url;
193 scw.WriteText(text);
196 base::Pickle pickle;
197 WriteToPickle(base::FilePath(), &pickle);
198 scw.WritePickledData(pickle,
199 ui::Clipboard::GetFormatType(kClipboardFormatString));
202 bool BookmarkNodeData::ReadFromClipboard(ui::ClipboardType type) {
203 DCHECK_EQ(type, ui::CLIPBOARD_TYPE_COPY_PASTE);
204 std::string data;
205 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
206 clipboard->ReadData(ui::Clipboard::GetFormatType(kClipboardFormatString),
207 &data);
209 if (!data.empty()) {
210 base::Pickle pickle(data.data(), static_cast<int>(data.size()));
211 if (ReadFromPickle(&pickle))
212 return true;
215 base::string16 title;
216 std::string url;
217 clipboard->ReadBookmark(&title, &url);
218 if (!url.empty()) {
219 Element element;
220 element.is_url = true;
221 element.url = GURL(url);
222 element.title = title;
224 elements.clear();
225 elements.push_back(element);
226 return true;
229 return false;
231 #endif
233 void BookmarkNodeData::WriteToPickle(const base::FilePath& profile_path,
234 base::Pickle* pickle) const {
235 profile_path.WriteToPickle(pickle);
236 pickle->WriteSizeT(size());
238 for (size_t i = 0; i < size(); ++i)
239 elements[i].WriteToPickle(pickle);
242 bool BookmarkNodeData::ReadFromPickle(base::Pickle* pickle) {
243 base::PickleIterator data_iterator(*pickle);
244 size_t element_count;
245 if (profile_path_.ReadFromPickle(&data_iterator) &&
246 data_iterator.ReadSizeT(&element_count)) {
247 std::vector<Element> tmp_elements;
248 tmp_elements.resize(element_count);
249 for (size_t i = 0; i < element_count; ++i) {
250 if (!tmp_elements[i].ReadFromPickle(&data_iterator)) {
251 return false;
254 elements.swap(tmp_elements);
257 return true;
260 std::vector<const BookmarkNode*> BookmarkNodeData::GetNodes(
261 BookmarkModel* model,
262 const base::FilePath& profile_path) const {
263 std::vector<const BookmarkNode*> nodes;
265 if (!IsFromProfilePath(profile_path))
266 return nodes;
268 for (size_t i = 0; i < size(); ++i) {
269 const BookmarkNode* node = GetBookmarkNodeByID(model, elements[i].id_);
270 if (!node) {
271 nodes.clear();
272 return nodes;
274 nodes.push_back(node);
276 return nodes;
279 const BookmarkNode* BookmarkNodeData::GetFirstNode(
280 BookmarkModel* model,
281 const base::FilePath& profile_path) const {
282 std::vector<const BookmarkNode*> nodes = GetNodes(model, profile_path);
283 return nodes.size() == 1 ? nodes[0] : NULL;
286 void BookmarkNodeData::Clear() {
287 profile_path_.clear();
288 elements.clear();
291 void BookmarkNodeData::SetOriginatingProfilePath(
292 const base::FilePath& profile_path) {
293 DCHECK(profile_path_.empty());
294 profile_path_ = profile_path;
297 bool BookmarkNodeData::IsFromProfilePath(
298 const base::FilePath& profile_path) const {
299 // An empty path means the data is not associated with any profile.
300 return !profile_path_.empty() && profile_path_ == profile_path;
303 } // namespace bookmarks