• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "chrome/browser/bookmarks/bookmark_node_data.h"
6 
7 #include <string>
8 
9 #include "base/basictypes.h"
10 #include "base/pickle.h"
11 #include "base/string_util.h"
12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/bookmarks/bookmark_model.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/url_constants.h"
16 #include "net/base/escape.h"
17 #include "ui/base/clipboard/scoped_clipboard_writer.h"
18 
19 #if defined(OS_MACOSX)
20 #include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
21 #else
22 #include "chrome/browser/browser_process.h"
23 #endif
24 
25 const char* BookmarkNodeData::kClipboardFormatString =
26     "chromium/x-bookmark-entries";
27 
Element()28 BookmarkNodeData::Element::Element() : is_url(false), id_(0) {
29 }
30 
Element(const BookmarkNode * node)31 BookmarkNodeData::Element::Element(const BookmarkNode* node)
32     : is_url(node->is_url()),
33       url(node->GetURL()),
34       title(node->GetTitle()),
35       id_(node->id()) {
36   for (int i = 0; i < node->child_count(); ++i)
37     children.push_back(Element(node->GetChild(i)));
38 }
39 
~Element()40 BookmarkNodeData::Element::~Element() {
41 }
42 
WriteToPickle(Pickle * pickle) const43 void BookmarkNodeData::Element::WriteToPickle(Pickle* pickle) const {
44   pickle->WriteBool(is_url);
45   pickle->WriteString(url.spec());
46   pickle->WriteString16(title);
47   pickle->WriteInt64(id_);
48   if (!is_url) {
49     pickle->WriteSize(children.size());
50     for (std::vector<Element>::const_iterator i = children.begin();
51          i != children.end(); ++i) {
52       i->WriteToPickle(pickle);
53     }
54   }
55 }
56 
ReadFromPickle(Pickle * pickle,void ** iterator)57 bool BookmarkNodeData::Element::ReadFromPickle(Pickle* pickle,
58                                                void** iterator) {
59   std::string url_spec;
60   if (!pickle->ReadBool(iterator, &is_url) ||
61       !pickle->ReadString(iterator, &url_spec) ||
62       !pickle->ReadString16(iterator, &title) ||
63       !pickle->ReadInt64(iterator, &id_)) {
64     return false;
65   }
66   url = GURL(url_spec);
67   children.clear();
68   if (!is_url) {
69     size_t children_count;
70     if (!pickle->ReadSize(iterator, &children_count))
71       return false;
72     children.resize(children_count);
73     for (std::vector<Element>::iterator i = children.begin();
74          i != children.end(); ++i) {
75       if (!i->ReadFromPickle(pickle, iterator))
76         return false;
77     }
78   }
79   return true;
80 }
81 
82 #if defined(TOOLKIT_VIEWS)
83 // static
GetBookmarkCustomFormat()84 ui::OSExchangeData::CustomFormat BookmarkNodeData::GetBookmarkCustomFormat() {
85   static ui::OSExchangeData::CustomFormat format;
86   static bool format_valid = false;
87 
88   if (!format_valid) {
89     format_valid = true;
90     format = ui::OSExchangeData::RegisterCustomFormat(
91         BookmarkNodeData::kClipboardFormatString);
92   }
93   return format;
94 }
95 #endif
96 
BookmarkNodeData()97 BookmarkNodeData::BookmarkNodeData() {
98 }
99 
BookmarkNodeData(const BookmarkNode * node)100 BookmarkNodeData::BookmarkNodeData(const BookmarkNode* node) {
101   elements.push_back(Element(node));
102 }
103 
BookmarkNodeData(const std::vector<const BookmarkNode * > & nodes)104 BookmarkNodeData::BookmarkNodeData(
105     const std::vector<const BookmarkNode*>& nodes) {
106   ReadFromVector(nodes);
107 }
108 
~BookmarkNodeData()109 BookmarkNodeData::~BookmarkNodeData() {
110 }
111 
ReadFromVector(const std::vector<const BookmarkNode * > & nodes)112 bool BookmarkNodeData::ReadFromVector(
113     const std::vector<const BookmarkNode*>& nodes) {
114   Clear();
115 
116   if (nodes.empty())
117     return false;
118 
119   for (size_t i = 0; i < nodes.size(); ++i)
120     elements.push_back(Element(nodes[i]));
121 
122   return true;
123 }
124 
ReadFromTuple(const GURL & url,const string16 & title)125 bool BookmarkNodeData::ReadFromTuple(const GURL& url, const string16& title) {
126   Clear();
127 
128   if (!url.is_valid())
129     return false;
130 
131   Element element;
132   element.title = title;
133   element.url = url;
134   element.is_url = true;
135 
136   elements.push_back(element);
137 
138   return true;
139 }
140 
141 #if !defined(OS_MACOSX)
WriteToClipboard(Profile * profile) const142 void BookmarkNodeData::WriteToClipboard(Profile* profile) const {
143   ui::ScopedClipboardWriter scw(g_browser_process->clipboard());
144 
145   // If there is only one element and it is a URL, write the URL to the
146   // clipboard.
147   if (elements.size() == 1 && elements[0].is_url) {
148     const string16& title = elements[0].title;
149     const std::string url = elements[0].url.spec();
150 
151     scw.WriteBookmark(title, url);
152     scw.WriteHyperlink(EscapeForHTML(title), url);
153 
154     // Also write the URL to the clipboard as text so that it can be pasted
155     // into text fields. We use WriteText instead of WriteURL because we don't
156     // want to clobber the X clipboard when the user copies out of the omnibox
157     // on Linux (on Windows and Mac, there is no difference between these
158     // functions).
159     scw.WriteText(UTF8ToUTF16(url));
160   }
161 
162   Pickle pickle;
163   WriteToPickle(profile, &pickle);
164   scw.WritePickledData(pickle, kClipboardFormatString);
165 }
166 
ReadFromClipboard()167 bool BookmarkNodeData::ReadFromClipboard() {
168   std::string data;
169   ui::Clipboard* clipboard = g_browser_process->clipboard();
170   clipboard->ReadData(kClipboardFormatString, &data);
171 
172   if (!data.empty()) {
173     Pickle pickle(data.data(), data.size());
174     if (ReadFromPickle(&pickle))
175       return true;
176   }
177 
178   string16 title;
179   std::string url;
180   clipboard->ReadBookmark(&title, &url);
181   if (!url.empty()) {
182     Element element;
183     element.is_url = true;
184     element.url = GURL(url);
185     element.title = title;
186 
187     elements.clear();
188     elements.push_back(element);
189     return true;
190   }
191 
192   return false;
193 }
194 
ClipboardContainsBookmarks()195 bool BookmarkNodeData::ClipboardContainsBookmarks() {
196   return g_browser_process->clipboard()->IsFormatAvailableByString(
197       BookmarkNodeData::kClipboardFormatString, ui::Clipboard::BUFFER_STANDARD);
198 }
199 #else
WriteToClipboard(Profile * profile) const200 void BookmarkNodeData::WriteToClipboard(Profile* profile) const {
201   bookmark_pasteboard_helper_mac::WriteToClipboard(elements, profile_path_);
202 }
203 
ReadFromClipboard()204 bool BookmarkNodeData::ReadFromClipboard() {
205   return bookmark_pasteboard_helper_mac::ReadFromClipboard(elements,
206                                                            &profile_path_);
207 }
208 
ReadFromDragClipboard()209 bool BookmarkNodeData::ReadFromDragClipboard() {
210   return bookmark_pasteboard_helper_mac::ReadFromDragClipboard(elements,
211                                                                &profile_path_);
212 }
213 
ClipboardContainsBookmarks()214 bool BookmarkNodeData::ClipboardContainsBookmarks() {
215   return bookmark_pasteboard_helper_mac::ClipboardContainsBookmarks();
216 }
217 #endif  // !defined(OS_MACOSX)
218 
219 #if defined(TOOLKIT_VIEWS)
Write(Profile * profile,ui::OSExchangeData * data) const220 void BookmarkNodeData::Write(Profile* profile, ui::OSExchangeData* data) const {
221   DCHECK(data);
222 
223   // If there is only one element and it is a URL, write the URL to the
224   // clipboard.
225   if (elements.size() == 1 && elements[0].is_url) {
226     if (elements[0].url.SchemeIs(chrome::kJavaScriptScheme)) {
227       data->SetString(UTF8ToUTF16(elements[0].url.spec()));
228     } else {
229       data->SetURL(elements[0].url, elements[0].title);
230     }
231   }
232 
233   Pickle data_pickle;
234   WriteToPickle(profile, &data_pickle);
235 
236   data->SetPickledData(GetBookmarkCustomFormat(), data_pickle);
237 }
238 
Read(const ui::OSExchangeData & data)239 bool BookmarkNodeData::Read(const ui::OSExchangeData& data) {
240   elements.clear();
241 
242   profile_path_.clear();
243 
244   if (data.HasCustomFormat(GetBookmarkCustomFormat())) {
245     Pickle drag_data_pickle;
246     if (data.GetPickledData(GetBookmarkCustomFormat(), &drag_data_pickle)) {
247       if (!ReadFromPickle(&drag_data_pickle))
248         return false;
249     }
250   } else {
251     // See if there is a URL on the clipboard.
252     Element element;
253     GURL url;
254     string16 title;
255     if (data.GetURLAndTitle(&url, &title))
256       ReadFromTuple(url, title);
257   }
258 
259   return is_valid();
260 }
261 #endif
262 
WriteToPickle(Profile * profile,Pickle * pickle) const263 void BookmarkNodeData::WriteToPickle(Profile* profile, Pickle* pickle) const {
264   FilePath path = profile ? profile->GetPath() : FilePath();
265   FilePath::WriteStringTypeToPickle(pickle, path.value());
266   pickle->WriteSize(elements.size());
267 
268   for (size_t i = 0; i < elements.size(); ++i)
269     elements[i].WriteToPickle(pickle);
270 }
271 
ReadFromPickle(Pickle * pickle)272 bool BookmarkNodeData::ReadFromPickle(Pickle* pickle) {
273   void* data_iterator = NULL;
274   size_t element_count;
275   if (FilePath::ReadStringTypeFromPickle(pickle, &data_iterator,
276                                          &profile_path_) &&
277       pickle->ReadSize(&data_iterator, &element_count)) {
278     std::vector<Element> tmp_elements;
279     tmp_elements.resize(element_count);
280     for (size_t i = 0; i < element_count; ++i) {
281       if (!tmp_elements[i].ReadFromPickle(pickle, &data_iterator)) {
282         return false;
283       }
284     }
285     elements.swap(tmp_elements);
286   }
287 
288   return true;
289 }
290 
GetNodes(Profile * profile) const291 std::vector<const BookmarkNode*> BookmarkNodeData::GetNodes(
292     Profile* profile) const {
293   std::vector<const BookmarkNode*> nodes;
294 
295   if (!IsFromProfile(profile))
296     return nodes;
297 
298   for (size_t i = 0; i < elements.size(); ++i) {
299     const BookmarkNode* node =
300         profile->GetBookmarkModel()->GetNodeByID(elements[i].id_);
301     if (!node) {
302       nodes.clear();
303       return nodes;
304     }
305     nodes.push_back(node);
306   }
307   return nodes;
308 }
309 
GetFirstNode(Profile * profile) const310 const BookmarkNode* BookmarkNodeData::GetFirstNode(Profile* profile) const {
311   std::vector<const BookmarkNode*> nodes = GetNodes(profile);
312   return nodes.size() == 1 ? nodes[0] : NULL;
313 }
314 
Clear()315 void BookmarkNodeData::Clear() {
316   profile_path_.clear();
317   elements.clear();
318 }
319 
SetOriginatingProfile(Profile * profile)320 void BookmarkNodeData::SetOriginatingProfile(Profile* profile) {
321   DCHECK(profile_path_.empty());
322 
323   if (profile)
324     profile_path_ = profile->GetPath().value();
325 }
326 
IsFromProfile(Profile * profile) const327 bool BookmarkNodeData::IsFromProfile(Profile* profile) const {
328   // An empty path means the data is not associated with any profile.
329   return !profile_path_.empty() && profile_path_ == profile->GetPath().value();
330 }
331