1 // Copyright (c) 2012 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 "chrome/browser/bookmarks/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 "chrome/browser/bookmarks/bookmark_model.h"
14 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
15 #include "chrome/browser/profiles/profile.h"
16 #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 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_);
44 pickle->WriteUInt64(children.size());
45 for (std::vector<Element>::const_iterator i = children.begin();
46 i != children.end(); ++i) {
47 i->WriteToPickle(pickle);
52 bool BookmarkNodeData::Element::ReadFromPickle(Pickle* pickle,
53 PickleIterator* iterator) {
55 if (!pickle->ReadBool(iterator, &is_url) ||
56 !pickle->ReadString(iterator, &url_spec) ||
57 !pickle->ReadString16(iterator, &title) ||
58 !pickle->ReadInt64(iterator, &id_)) {
62 date_added = base::Time();
63 date_folder_modified = base::Time();
66 uint64 children_count;
67 if (!pickle->ReadUInt64(iterator, &children_count))
69 children.reserve(children_count);
70 for (uint64 i = 0; i < children_count; ++i) {
71 children.push_back(Element());
72 if (!children.back().ReadFromPickle(pickle, iterator))
79 // BookmarkNodeData -----------------------------------------------------------
81 BookmarkNodeData::BookmarkNodeData() {
84 BookmarkNodeData::BookmarkNodeData(const BookmarkNode* node) {
85 elements.push_back(Element(node));
88 BookmarkNodeData::BookmarkNodeData(
89 const std::vector<const BookmarkNode*>& nodes) {
90 ReadFromVector(nodes);
93 BookmarkNodeData::~BookmarkNodeData() {
96 #if !defined(OS_MACOSX)
98 bool BookmarkNodeData::ClipboardContainsBookmarks() {
99 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
100 ui::Clipboard::GetFormatType(kClipboardFormatString),
101 ui::CLIPBOARD_TYPE_COPY_PASTE);
105 bool BookmarkNodeData::ReadFromVector(
106 const std::vector<const BookmarkNode*>& nodes) {
112 for (size_t i = 0; i < nodes.size(); ++i)
113 elements.push_back(Element(nodes[i]));
118 bool BookmarkNodeData::ReadFromTuple(const GURL& url, const string16& title) {
125 element.title = title;
127 element.is_url = true;
129 elements.push_back(element);
134 #if !defined(OS_MACOSX)
135 void BookmarkNodeData::WriteToClipboard(ui::ClipboardType type) {
136 DCHECK_EQ(type, ui::CLIPBOARD_TYPE_COPY_PASTE);
137 ui::ScopedClipboardWriter scw(ui::Clipboard::GetForCurrentThread(),
138 ui::CLIPBOARD_TYPE_COPY_PASTE);
140 // If there is only one element and it is a URL, write the URL to the
142 if (elements.size() == 1 && elements[0].is_url) {
143 const string16& title = elements[0].title;
144 const std::string url = elements[0].url.spec();
146 scw.WriteBookmark(title, url);
148 // Don't call scw.WriteHyperlink() here, since some rich text editors will
149 // change fonts when such data is pasted in; besides, most such editors
150 // auto-linkify at some point anyway.
152 // Also write the URL to the clipboard as text so that it can be pasted
153 // into text fields. We use WriteText instead of WriteURL because we don't
154 // want to clobber the X clipboard when the user copies out of the omnibox
155 // on Linux (on Windows and Mac, there is no difference between these
157 scw.WriteText(UTF8ToUTF16(url));
161 WriteToPickle(NULL, &pickle);
162 scw.WritePickledData(pickle,
163 ui::Clipboard::GetFormatType(kClipboardFormatString));
166 bool BookmarkNodeData::ReadFromClipboard(ui::ClipboardType type) {
167 DCHECK_EQ(type, ui::CLIPBOARD_TYPE_COPY_PASTE);
169 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
170 clipboard->ReadData(ui::Clipboard::GetFormatType(kClipboardFormatString),
174 Pickle pickle(data.data(), data.size());
175 if (ReadFromPickle(&pickle))
181 clipboard->ReadBookmark(&title, &url);
184 element.is_url = true;
185 element.url = GURL(url);
186 element.title = title;
189 elements.push_back(element);
197 void BookmarkNodeData::WriteToPickle(Profile* profile, Pickle* pickle) const {
198 base::FilePath path = profile ? profile->GetPath() : base::FilePath();
199 path.WriteToPickle(pickle);
200 pickle->WriteUInt64(elements.size());
202 for (size_t i = 0; i < elements.size(); ++i)
203 elements[i].WriteToPickle(pickle);
206 bool BookmarkNodeData::ReadFromPickle(Pickle* pickle) {
207 PickleIterator data_iterator(*pickle);
208 uint64 element_count;
209 if (profile_path_.ReadFromPickle(&data_iterator) &&
210 pickle->ReadUInt64(&data_iterator, &element_count)) {
211 std::vector<Element> tmp_elements;
212 tmp_elements.resize(element_count);
213 for (uint64 i = 0; i < element_count; ++i) {
214 if (!tmp_elements[i].ReadFromPickle(pickle, &data_iterator)) {
218 elements.swap(tmp_elements);
224 std::vector<const BookmarkNode*> BookmarkNodeData::GetNodes(
225 Profile* profile) const {
226 std::vector<const BookmarkNode*> nodes;
228 if (!IsFromProfile(profile))
231 for (size_t i = 0; i < elements.size(); ++i) {
232 const BookmarkNode* node = BookmarkModelFactory::GetForProfile(
233 profile)->GetNodeByID(elements[i].id_);
238 nodes.push_back(node);
243 const BookmarkNode* BookmarkNodeData::GetFirstNode(Profile* profile) const {
244 std::vector<const BookmarkNode*> nodes = GetNodes(profile);
245 return nodes.size() == 1 ? nodes[0] : NULL;
248 void BookmarkNodeData::Clear() {
249 profile_path_.clear();
253 void BookmarkNodeData::SetOriginatingProfile(Profile* profile) {
254 DCHECK(profile_path_.empty());
257 profile_path_ = profile->GetPath();
260 bool BookmarkNodeData::IsFromProfile(Profile* profile) const {
261 // An empty path means the data is not associated with any profile.
262 return !profile_path_.empty() && profile_path_ == profile->GetPath();