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"
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"
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()),
26 title(node
->GetTitle()),
27 date_added(node
->date_added()),
28 date_folder_modified(node
->date_folder_modified()),
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
);
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
) {
61 if (!iterator
->ReadBool(&is_url
) ||
62 !iterator
->ReadString(&url_spec
) ||
63 !iterator
->ReadString16(&title
) ||
64 !iterator
->ReadInt64(&id_
)) {
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
))
74 for (size_t i
= 0; i
< meta_field_count
; ++i
) {
77 if (!iterator
->ReadString(&key
) ||
78 !iterator
->ReadString(&value
)) {
81 meta_info_map
[key
] = value
;
85 size_t children_count
;
86 if (!iterator
->ReadSizeT(&children_count
))
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
))
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)
117 bool BookmarkNodeData::ClipboardContainsBookmarks() {
118 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
119 ui::Clipboard::GetFormatType(kClipboardFormatString
),
120 ui::CLIPBOARD_TYPE_COPY_PASTE
);
124 bool BookmarkNodeData::ReadFromVector(
125 const std::vector
<const BookmarkNode
*>& nodes
) {
131 for (size_t i
= 0; i
< nodes
.size(); ++i
)
132 elements
.push_back(Element(nodes
[i
]));
137 bool BookmarkNodeData::ReadFromTuple(const GURL
& url
,
138 const base::string16
& title
) {
145 element
.title
= title
;
147 element
.is_url
= true;
149 elements
.push_back(element
);
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
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
177 scw
.WriteText(base::UTF8ToUTF16(url
));
179 // We have either more than one URL, a folder, or a combination of URLs
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
;
189 const base::string16 url
= base::UTF8ToUTF16(elements
[i
].url
.spec());
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
);
205 ui::Clipboard
* clipboard
= ui::Clipboard::GetForCurrentThread();
206 clipboard
->ReadData(ui::Clipboard::GetFormatType(kClipboardFormatString
),
210 base::Pickle
pickle(data
.data(), static_cast<int>(data
.size()));
211 if (ReadFromPickle(&pickle
))
215 base::string16 title
;
217 clipboard
->ReadBookmark(&title
, &url
);
220 element
.is_url
= true;
221 element
.url
= GURL(url
);
222 element
.title
= title
;
225 elements
.push_back(element
);
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
)) {
254 elements
.swap(tmp_elements
);
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
))
268 for (size_t i
= 0; i
< size(); ++i
) {
269 const BookmarkNode
* node
= GetBookmarkNodeByID(model
, elements
[i
].id_
);
274 nodes
.push_back(node
);
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();
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