• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "components/bookmarks/browser/bookmark_node_data.h"
6 
7 #include <string>
8 
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"
15 
16 const char* BookmarkNodeData::kClipboardFormatString =
17     "chromium/x-bookmark-entries";
18 
Element()19 BookmarkNodeData::Element::Element() : is_url(false), id_(0) {
20 }
21 
Element(const BookmarkNode * node)22 BookmarkNodeData::Element::Element(const BookmarkNode* node)
23     : is_url(node->is_url()),
24       url(node->url()),
25       title(node->GetTitle()),
26       date_added(node->date_added()),
27       date_folder_modified(node->date_folder_modified()),
28       id_(node->id()) {
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)));
33 }
34 
~Element()35 BookmarkNodeData::Element::~Element() {
36 }
37 
WriteToPickle(Pickle * pickle) const38 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);
48   }
49   if (!is_url) {
50     pickle->WriteUInt64(children.size());
51     for (std::vector<Element>::const_iterator i = children.begin();
52          i != children.end(); ++i) {
53       i->WriteToPickle(pickle);
54     }
55   }
56 }
57 
ReadFromPickle(Pickle * pickle,PickleIterator * iterator)58 bool BookmarkNodeData::Element::ReadFromPickle(Pickle* pickle,
59                                                PickleIterator* iterator) {
60   std::string url_spec;
61   if (!pickle->ReadBool(iterator, &is_url) ||
62       !pickle->ReadString(iterator, &url_spec) ||
63       !pickle->ReadString16(iterator, &title) ||
64       !pickle->ReadInt64(iterator, &id_)) {
65     return false;
66   }
67   url = GURL(url_spec);
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))
73     return false;
74   for (uint64 i = 0; i < meta_field_count; ++i) {
75     std::string key;
76     std::string value;
77     if (!pickle->ReadString(iterator, &key) ||
78         !pickle->ReadString(iterator, &value)) {
79       return false;
80     }
81     meta_info_map[key] = value;
82   }
83   children.clear();
84   if (!is_url) {
85     uint64 children_count;
86     if (!pickle->ReadUInt64(iterator, &children_count))
87       return false;
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))
92         return false;
93     }
94   }
95   return true;
96 }
97 
98 // BookmarkNodeData -----------------------------------------------------------
99 
BookmarkNodeData()100 BookmarkNodeData::BookmarkNodeData() {
101 }
102 
BookmarkNodeData(const BookmarkNode * node)103 BookmarkNodeData::BookmarkNodeData(const BookmarkNode* node) {
104   elements.push_back(Element(node));
105 }
106 
BookmarkNodeData(const std::vector<const BookmarkNode * > & nodes)107 BookmarkNodeData::BookmarkNodeData(
108     const std::vector<const BookmarkNode*>& nodes) {
109   ReadFromVector(nodes);
110 }
111 
~BookmarkNodeData()112 BookmarkNodeData::~BookmarkNodeData() {
113 }
114 
115 #if !defined(OS_MACOSX)
116 // static
ClipboardContainsBookmarks()117 bool BookmarkNodeData::ClipboardContainsBookmarks() {
118   return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
119       ui::Clipboard::GetFormatType(kClipboardFormatString),
120       ui::CLIPBOARD_TYPE_COPY_PASTE);
121 }
122 #endif
123 
ReadFromVector(const std::vector<const BookmarkNode * > & nodes)124 bool BookmarkNodeData::ReadFromVector(
125     const std::vector<const BookmarkNode*>& nodes) {
126   Clear();
127 
128   if (nodes.empty())
129     return false;
130 
131   for (size_t i = 0; i < nodes.size(); ++i)
132     elements.push_back(Element(nodes[i]));
133 
134   return true;
135 }
136 
ReadFromTuple(const GURL & url,const base::string16 & title)137 bool BookmarkNodeData::ReadFromTuple(const GURL& url,
138                                      const base::string16& title) {
139   Clear();
140 
141   if (!url.is_valid())
142     return false;
143 
144   Element element;
145   element.title = title;
146   element.url = url;
147   element.is_url = true;
148 
149   elements.push_back(element);
150 
151   return true;
152 }
153 
154 #if !defined(OS_MACOSX)
WriteToClipboard(ui::ClipboardType clipboard_type)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(),
159                                 clipboard_type);
160 
161   // If there is only one element and it is a URL, write the URL to the
162   // clipboard.
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();
166 
167     scw.WriteBookmark(title, url);
168 
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.
172 
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
177     // functions).
178     scw.WriteText(base::UTF8ToUTF16(url));
179   }
180 
181   Pickle pickle;
182   WriteToPickle(base::FilePath(), &pickle);
183   scw.WritePickledData(pickle,
184                        ui::Clipboard::GetFormatType(kClipboardFormatString));
185 }
186 
ReadFromClipboard(ui::ClipboardType type)187 bool BookmarkNodeData::ReadFromClipboard(ui::ClipboardType type) {
188   DCHECK_EQ(type, ui::CLIPBOARD_TYPE_COPY_PASTE);
189   std::string data;
190   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
191   clipboard->ReadData(ui::Clipboard::GetFormatType(kClipboardFormatString),
192                       &data);
193 
194   if (!data.empty()) {
195     Pickle pickle(data.data(), static_cast<int>(data.size()));
196     if (ReadFromPickle(&pickle))
197       return true;
198   }
199 
200   base::string16 title;
201   std::string url;
202   clipboard->ReadBookmark(&title, &url);
203   if (!url.empty()) {
204     Element element;
205     element.is_url = true;
206     element.url = GURL(url);
207     element.title = title;
208 
209     elements.clear();
210     elements.push_back(element);
211     return true;
212   }
213 
214   return false;
215 }
216 #endif
217 
WriteToPickle(const base::FilePath & profile_path,Pickle * pickle) const218 void BookmarkNodeData::WriteToPickle(const base::FilePath& profile_path,
219                                      Pickle* pickle) const {
220   profile_path.WriteToPickle(pickle);
221   pickle->WriteUInt64(elements.size());
222 
223   for (size_t i = 0; i < elements.size(); ++i)
224     elements[i].WriteToPickle(pickle);
225 }
226 
ReadFromPickle(Pickle * 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)) {
236         return false;
237       }
238     }
239     elements.swap(tmp_elements);
240   }
241 
242   return true;
243 }
244 
GetNodes(BookmarkModel * model,const base::FilePath & profile_path) const245 std::vector<const BookmarkNode*> BookmarkNodeData::GetNodes(
246     BookmarkModel* model,
247     const base::FilePath& profile_path) const {
248   std::vector<const BookmarkNode*> nodes;
249 
250   if (!IsFromProfilePath(profile_path))
251     return nodes;
252 
253   for (size_t i = 0; i < elements.size(); ++i) {
254     const BookmarkNode* node = GetBookmarkNodeByID(model, elements[i].id_);
255     if (!node) {
256       nodes.clear();
257       return nodes;
258     }
259     nodes.push_back(node);
260   }
261   return nodes;
262 }
263 
GetFirstNode(BookmarkModel * model,const base::FilePath & profile_path) const264 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;
269 }
270 
Clear()271 void BookmarkNodeData::Clear() {
272   profile_path_.clear();
273   elements.clear();
274 }
275 
SetOriginatingProfilePath(const base::FilePath & profile_path)276 void BookmarkNodeData::SetOriginatingProfilePath(
277     const base::FilePath& profile_path) {
278   DCHECK(profile_path_.empty());
279   profile_path_ = profile_path;
280 }
281 
IsFromProfilePath(const base::FilePath & profile_path) const282 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;
286 }
287