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"
18 const char* BookmarkNodeData::kClipboardFormatString
=
19 "chromium/x-bookmark-entries";
21 BookmarkNodeData::Element::Element() : is_url(false), id_(0) {
24 BookmarkNodeData::Element::Element(const BookmarkNode
* node
)
25 : is_url(node
->is_url()),
27 title(node
->GetTitle()),
28 date_added(node
->date_added()),
29 date_folder_modified(node
->date_folder_modified()),
31 if (node
->GetMetaInfoMap())
32 meta_info_map
= *node
->GetMetaInfoMap();
33 for (int i
= 0; i
< node
->child_count(); ++i
)
34 children
.push_back(Element(node
->GetChild(i
)));
37 BookmarkNodeData::Element::~Element() {
40 void BookmarkNodeData::Element::WriteToPickle(Pickle
* pickle
) const {
41 pickle
->WriteBool(is_url
);
42 pickle
->WriteString(url
.spec());
43 pickle
->WriteString16(title
);
44 pickle
->WriteInt64(id_
);
45 pickle
->WriteSizeT(meta_info_map
.size());
46 for (BookmarkNode::MetaInfoMap::const_iterator it
= meta_info_map
.begin();
47 it
!= meta_info_map
.end(); ++it
) {
48 pickle
->WriteString(it
->first
);
49 pickle
->WriteString(it
->second
);
52 pickle
->WriteSizeT(children
.size());
53 for (std::vector
<Element
>::const_iterator i
= children
.begin();
54 i
!= children
.end(); ++i
) {
55 i
->WriteToPickle(pickle
);
60 bool BookmarkNodeData::Element::ReadFromPickle(PickleIterator
* iterator
) {
62 if (!iterator
->ReadBool(&is_url
) ||
63 !iterator
->ReadString(&url_spec
) ||
64 !iterator
->ReadString16(&title
) ||
65 !iterator
->ReadInt64(&id_
)) {
69 date_added
= base::Time();
70 date_folder_modified
= base::Time();
71 meta_info_map
.clear();
72 size_t meta_field_count
;
73 if (!iterator
->ReadSizeT(&meta_field_count
))
75 for (size_t i
= 0; i
< meta_field_count
; ++i
) {
78 if (!iterator
->ReadString(&key
) ||
79 !iterator
->ReadString(&value
)) {
82 meta_info_map
[key
] = value
;
86 size_t children_count
;
87 if (!iterator
->ReadSizeT(&children_count
))
89 children
.reserve(children_count
);
90 for (size_t i
= 0; i
< children_count
; ++i
) {
91 children
.push_back(Element());
92 if (!children
.back().ReadFromPickle(iterator
))
99 // BookmarkNodeData -----------------------------------------------------------
101 BookmarkNodeData::BookmarkNodeData() {
104 BookmarkNodeData::BookmarkNodeData(const BookmarkNode
* node
) {
105 elements
.push_back(Element(node
));
108 BookmarkNodeData::BookmarkNodeData(
109 const std::vector
<const BookmarkNode
*>& nodes
) {
110 ReadFromVector(nodes
);
113 BookmarkNodeData::~BookmarkNodeData() {
116 #if !defined(OS_MACOSX)
118 bool BookmarkNodeData::ClipboardContainsBookmarks() {
119 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
120 ui::Clipboard::GetFormatType(kClipboardFormatString
),
121 ui::CLIPBOARD_TYPE_COPY_PASTE
);
125 bool BookmarkNodeData::ReadFromVector(
126 const std::vector
<const BookmarkNode
*>& nodes
) {
132 for (size_t i
= 0; i
< nodes
.size(); ++i
)
133 elements
.push_back(Element(nodes
[i
]));
138 bool BookmarkNodeData::ReadFromTuple(const GURL
& url
,
139 const base::string16
& title
) {
146 element
.title
= title
;
148 element
.is_url
= true;
150 elements
.push_back(element
);
155 #if !defined(OS_MACOSX)
156 void BookmarkNodeData::WriteToClipboard(ui::ClipboardType clipboard_type
) {
157 DCHECK(clipboard_type
== ui::CLIPBOARD_TYPE_COPY_PASTE
||
158 clipboard_type
== ui::CLIPBOARD_TYPE_SELECTION
);
159 ui::ScopedClipboardWriter
scw(clipboard_type
);
161 // If there is only one element and it is a URL, write the URL to the
163 if (has_single_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
));
180 // We have either more than one URL, a folder, or a combination of URLs
183 for (size_t i
= 0; i
< size(); i
++) {
184 text
+= i
== 0 ? base::ASCIIToUTF16("") : base::ASCIIToUTF16("\n");
185 if (!elements
[i
].is_url
) {
186 // Then it's a folder. Only copy the name of the folder.
187 const base::string16 title
= elements
[i
].title
;
190 const base::string16 url
= base::UTF8ToUTF16(elements
[i
].url
.spec());
198 WriteToPickle(base::FilePath(), &pickle
);
199 scw
.WritePickledData(pickle
,
200 ui::Clipboard::GetFormatType(kClipboardFormatString
));
203 bool BookmarkNodeData::ReadFromClipboard(ui::ClipboardType type
) {
204 DCHECK_EQ(type
, ui::CLIPBOARD_TYPE_COPY_PASTE
);
206 ui::Clipboard
* clipboard
= ui::Clipboard::GetForCurrentThread();
207 clipboard
->ReadData(ui::Clipboard::GetFormatType(kClipboardFormatString
),
211 Pickle
pickle(data
.data(), static_cast<int>(data
.size()));
212 if (ReadFromPickle(&pickle
))
216 base::string16 title
;
218 clipboard
->ReadBookmark(&title
, &url
);
221 element
.is_url
= true;
222 element
.url
= GURL(url
);
223 element
.title
= title
;
226 elements
.push_back(element
);
234 void BookmarkNodeData::WriteToPickle(const base::FilePath
& profile_path
,
235 Pickle
* pickle
) const {
236 profile_path
.WriteToPickle(pickle
);
237 pickle
->WriteSizeT(size());
239 for (size_t i
= 0; i
< size(); ++i
)
240 elements
[i
].WriteToPickle(pickle
);
243 bool BookmarkNodeData::ReadFromPickle(Pickle
* pickle
) {
244 PickleIterator
data_iterator(*pickle
);
245 size_t element_count
;
246 if (profile_path_
.ReadFromPickle(&data_iterator
) &&
247 data_iterator
.ReadSizeT(&element_count
)) {
248 std::vector
<Element
> tmp_elements
;
249 tmp_elements
.resize(element_count
);
250 for (size_t i
= 0; i
< element_count
; ++i
) {
251 if (!tmp_elements
[i
].ReadFromPickle(&data_iterator
)) {
255 elements
.swap(tmp_elements
);
261 std::vector
<const BookmarkNode
*> BookmarkNodeData::GetNodes(
262 BookmarkModel
* model
,
263 const base::FilePath
& profile_path
) const {
264 std::vector
<const BookmarkNode
*> nodes
;
266 if (!IsFromProfilePath(profile_path
))
269 for (size_t i
= 0; i
< size(); ++i
) {
270 const BookmarkNode
* node
= GetBookmarkNodeByID(model
, elements
[i
].id_
);
275 nodes
.push_back(node
);
280 const BookmarkNode
* BookmarkNodeData::GetFirstNode(
281 BookmarkModel
* model
,
282 const base::FilePath
& profile_path
) const {
283 std::vector
<const BookmarkNode
*> nodes
= GetNodes(model
, profile_path
);
284 return nodes
.size() == 1 ? nodes
[0] : NULL
;
287 void BookmarkNodeData::Clear() {
288 profile_path_
.clear();
292 void BookmarkNodeData::SetOriginatingProfilePath(
293 const base::FilePath
& profile_path
) {
294 DCHECK(profile_path_
.empty());
295 profile_path_
= profile_path
;
298 bool BookmarkNodeData::IsFromProfilePath(
299 const base::FilePath
& profile_path
) const {
300 // An empty path means the data is not associated with any profile.
301 return !profile_path_
.empty() && profile_path_
== profile_path
;
304 } // namespace bookmarks