Home | History | Annotate | Download | only in bookmarks
      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 
     28 BookmarkNodeData::Element::Element() : is_url(false), id_(0) {
     29 }
     30 
     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 
     40 BookmarkNodeData::Element::~Element() {
     41 }
     42 
     43 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 
     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
     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 
     97 BookmarkNodeData::BookmarkNodeData() {
     98 }
     99 
    100 BookmarkNodeData::BookmarkNodeData(const BookmarkNode* node) {
    101   elements.push_back(Element(node));
    102 }
    103 
    104 BookmarkNodeData::BookmarkNodeData(
    105     const std::vector<const BookmarkNode*>& nodes) {
    106   ReadFromVector(nodes);
    107 }
    108 
    109 BookmarkNodeData::~BookmarkNodeData() {
    110 }
    111 
    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 
    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)
    142 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 
    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 
    195 bool BookmarkNodeData::ClipboardContainsBookmarks() {
    196   return g_browser_process->clipboard()->IsFormatAvailableByString(
    197       BookmarkNodeData::kClipboardFormatString, ui::Clipboard::BUFFER_STANDARD);
    198 }
    199 #else
    200 void BookmarkNodeData::WriteToClipboard(Profile* profile) const {
    201   bookmark_pasteboard_helper_mac::WriteToClipboard(elements, profile_path_);
    202 }
    203 
    204 bool BookmarkNodeData::ReadFromClipboard() {
    205   return bookmark_pasteboard_helper_mac::ReadFromClipboard(elements,
    206                                                            &profile_path_);
    207 }
    208 
    209 bool BookmarkNodeData::ReadFromDragClipboard() {
    210   return bookmark_pasteboard_helper_mac::ReadFromDragClipboard(elements,
    211                                                                &profile_path_);
    212 }
    213 
    214 bool BookmarkNodeData::ClipboardContainsBookmarks() {
    215   return bookmark_pasteboard_helper_mac::ClipboardContainsBookmarks();
    216 }
    217 #endif  // !defined(OS_MACOSX)
    218 
    219 #if defined(TOOLKIT_VIEWS)
    220 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 
    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 
    263 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 
    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 
    291 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 
    310 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 
    315 void BookmarkNodeData::Clear() {
    316   profile_path_.clear();
    317   elements.clear();
    318 }
    319 
    320 void BookmarkNodeData::SetOriginatingProfile(Profile* profile) {
    321   DCHECK(profile_path_.empty());
    322 
    323   if (profile)
    324     profile_path_ = profile->GetPath().value();
    325 }
    326 
    327 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