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/basictypes.h"
10 #include "base/pickle.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "components/bookmarks/browser/bookmark_utils.h"
14 #include "ui/base/clipboard/scoped_clipboard_writer.h"
16 const char* BookmarkNodeData::kClipboardFormatString
=
17 "chromium/x-bookmark-entries";
19 BookmarkNodeData::Element::Element() : is_url(false), id_(0) {
22 BookmarkNodeData::Element::Element(const BookmarkNode
* node
)
23 : is_url(node
->is_url()),
25 title(node
->GetTitle()),
26 date_added(node
->date_added()),
27 date_folder_modified(node
->date_folder_modified()),
29 if (node
->GetMetaInfoMap())
30 meta_info_map
= *node
->GetMetaInfoMap();
31 for (int i
= 0; i
< node
->child_count(); ++i
)
32 children
.push_back(Element(node
->GetChild(i
)));
35 BookmarkNodeData::Element::~Element() {
38 void BookmarkNodeData::Element::WriteToPickle(Pickle
* pickle
) const {
39 pickle
->WriteBool(is_url
);
40 pickle
->WriteString(url
.spec());
41 pickle
->WriteString16(title
);
42 pickle
->WriteInt64(id_
);
43 pickle
->WriteUInt64(meta_info_map
.size());
44 for (BookmarkNode::MetaInfoMap::const_iterator it
= meta_info_map
.begin();
45 it
!= meta_info_map
.end(); ++it
) {
46 pickle
->WriteString(it
->first
);
47 pickle
->WriteString(it
->second
);
50 pickle
->WriteUInt64(children
.size());
51 for (std::vector
<Element
>::const_iterator i
= children
.begin();
52 i
!= children
.end(); ++i
) {
53 i
->WriteToPickle(pickle
);
58 bool BookmarkNodeData::Element::ReadFromPickle(Pickle
* pickle
,
59 PickleIterator
* iterator
) {
61 if (!pickle
->ReadBool(iterator
, &is_url
) ||
62 !pickle
->ReadString(iterator
, &url_spec
) ||
63 !pickle
->ReadString16(iterator
, &title
) ||
64 !pickle
->ReadInt64(iterator
, &id_
)) {
68 date_added
= base::Time();
69 date_folder_modified
= base::Time();
70 meta_info_map
.clear();
71 uint64 meta_field_count
;
72 if (!pickle
->ReadUInt64(iterator
, &meta_field_count
))
74 for (uint64 i
= 0; i
< meta_field_count
; ++i
) {
77 if (!pickle
->ReadString(iterator
, &key
) ||
78 !pickle
->ReadString(iterator
, &value
)) {
81 meta_info_map
[key
] = value
;
85 uint64 children_count
;
86 if (!pickle
->ReadUInt64(iterator
, &children_count
))
88 children
.reserve(children_count
);
89 for (uint64 i
= 0; i
< children_count
; ++i
) {
90 children
.push_back(Element());
91 if (!children
.back().ReadFromPickle(pickle
, 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(ui::Clipboard::GetForCurrentThread(),
161 // If there is only one element and it is a URL, write the URL to the
163 if (elements
.size() == 1 && elements
[0].is_url
) {
164 const base::string16
& title
= elements
[0].title
;
165 const std::string url
= elements
[0].url
.spec();
167 scw
.WriteBookmark(title
, url
);
169 // Don't call scw.WriteHyperlink() here, since some rich text editors will
170 // change fonts when such data is pasted in; besides, most such editors
171 // auto-linkify at some point anyway.
173 // Also write the URL to the clipboard as text so that it can be pasted
174 // into text fields. We use WriteText instead of WriteURL because we don't
175 // want to clobber the X clipboard when the user copies out of the omnibox
176 // on Linux (on Windows and Mac, there is no difference between these
178 scw
.WriteText(base::UTF8ToUTF16(url
));
182 WriteToPickle(base::FilePath(), &pickle
);
183 scw
.WritePickledData(pickle
,
184 ui::Clipboard::GetFormatType(kClipboardFormatString
));
187 bool BookmarkNodeData::ReadFromClipboard(ui::ClipboardType type
) {
188 DCHECK_EQ(type
, ui::CLIPBOARD_TYPE_COPY_PASTE
);
190 ui::Clipboard
* clipboard
= ui::Clipboard::GetForCurrentThread();
191 clipboard
->ReadData(ui::Clipboard::GetFormatType(kClipboardFormatString
),
195 Pickle
pickle(data
.data(), static_cast<int>(data
.size()));
196 if (ReadFromPickle(&pickle
))
200 base::string16 title
;
202 clipboard
->ReadBookmark(&title
, &url
);
205 element
.is_url
= true;
206 element
.url
= GURL(url
);
207 element
.title
= title
;
210 elements
.push_back(element
);
218 void BookmarkNodeData::WriteToPickle(const base::FilePath
& profile_path
,
219 Pickle
* pickle
) const {
220 profile_path
.WriteToPickle(pickle
);
221 pickle
->WriteUInt64(elements
.size());
223 for (size_t i
= 0; i
< elements
.size(); ++i
)
224 elements
[i
].WriteToPickle(pickle
);
227 bool BookmarkNodeData::ReadFromPickle(Pickle
* pickle
) {
228 PickleIterator
data_iterator(*pickle
);
229 uint64 element_count
;
230 if (profile_path_
.ReadFromPickle(&data_iterator
) &&
231 pickle
->ReadUInt64(&data_iterator
, &element_count
)) {
232 std::vector
<Element
> tmp_elements
;
233 tmp_elements
.resize(element_count
);
234 for (uint64 i
= 0; i
< element_count
; ++i
) {
235 if (!tmp_elements
[i
].ReadFromPickle(pickle
, &data_iterator
)) {
239 elements
.swap(tmp_elements
);
245 std::vector
<const BookmarkNode
*> BookmarkNodeData::GetNodes(
246 BookmarkModel
* model
,
247 const base::FilePath
& profile_path
) const {
248 std::vector
<const BookmarkNode
*> nodes
;
250 if (!IsFromProfilePath(profile_path
))
253 for (size_t i
= 0; i
< elements
.size(); ++i
) {
254 const BookmarkNode
* node
= GetBookmarkNodeByID(model
, elements
[i
].id_
);
259 nodes
.push_back(node
);
264 const BookmarkNode
* BookmarkNodeData::GetFirstNode(
265 BookmarkModel
* model
,
266 const base::FilePath
& profile_path
) const {
267 std::vector
<const BookmarkNode
*> nodes
= GetNodes(model
, profile_path
);
268 return nodes
.size() == 1 ? nodes
[0] : NULL
;
271 void BookmarkNodeData::Clear() {
272 profile_path_
.clear();
276 void BookmarkNodeData::SetOriginatingProfilePath(
277 const base::FilePath
& profile_path
) {
278 DCHECK(profile_path_
.empty());
279 profile_path_
= profile_path
;
282 bool BookmarkNodeData::IsFromProfilePath(
283 const base::FilePath
& profile_path
) const {
284 // An empty path means the data is not associated with any profile.
285 return !profile_path_
.empty() && profile_path_
== profile_path
;