Home | History | Annotate | Download | only in bookmarks
      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.
      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/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"
     17 
     18 const char* BookmarkNodeData::kClipboardFormatString =
     19     "chromium/x-bookmark-entries";
     20 
     21 BookmarkNodeData::Element::Element() : is_url(false), id_(0) {
     22 }
     23 
     24 BookmarkNodeData::Element::Element(const BookmarkNode* node)
     25     : is_url(node->is_url()),
     26       url(node->url()),
     27       title(node->GetTitle()),
     28       date_added(node->date_added()),
     29       date_folder_modified(node->date_folder_modified()),
     30       id_(node->id()) {
     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)));
     35 }
     36 
     37 BookmarkNodeData::Element::~Element() {
     38 }
     39 
     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->WriteUInt64(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);
     50   }
     51   if (!is_url) {
     52     pickle->WriteUInt64(children.size());
     53     for (std::vector<Element>::const_iterator i = children.begin();
     54          i != children.end(); ++i) {
     55       i->WriteToPickle(pickle);
     56     }
     57   }
     58 }
     59 
     60 bool BookmarkNodeData::Element::ReadFromPickle(Pickle* pickle,
     61                                                PickleIterator* iterator) {
     62   std::string url_spec;
     63   if (!pickle->ReadBool(iterator, &is_url) ||
     64       !pickle->ReadString(iterator, &url_spec) ||
     65       !pickle->ReadString16(iterator, &title) ||
     66       !pickle->ReadInt64(iterator, &id_)) {
     67     return false;
     68   }
     69   url = GURL(url_spec);
     70   date_added = base::Time();
     71   date_folder_modified = base::Time();
     72   meta_info_map.clear();
     73   uint64 meta_field_count;
     74   if (!pickle->ReadUInt64(iterator, &meta_field_count))
     75     return false;
     76   for (uint64 i = 0; i < meta_field_count; ++i) {
     77     std::string key;
     78     std::string value;
     79     if (!pickle->ReadString(iterator, &key) ||
     80         !pickle->ReadString(iterator, &value)) {
     81       return false;
     82     }
     83     meta_info_map[key] = value;
     84   }
     85   children.clear();
     86   if (!is_url) {
     87     uint64 children_count;
     88     if (!pickle->ReadUInt64(iterator, &children_count))
     89       return false;
     90     children.reserve(children_count);
     91     for (uint64 i = 0; i < children_count; ++i) {
     92       children.push_back(Element());
     93       if (!children.back().ReadFromPickle(pickle, iterator))
     94         return false;
     95     }
     96   }
     97   return true;
     98 }
     99 
    100 // BookmarkNodeData -----------------------------------------------------------
    101 
    102 BookmarkNodeData::BookmarkNodeData() {
    103 }
    104 
    105 BookmarkNodeData::BookmarkNodeData(const BookmarkNode* node) {
    106   elements.push_back(Element(node));
    107 }
    108 
    109 BookmarkNodeData::BookmarkNodeData(
    110     const std::vector<const BookmarkNode*>& nodes) {
    111   ReadFromVector(nodes);
    112 }
    113 
    114 BookmarkNodeData::~BookmarkNodeData() {
    115 }
    116 
    117 #if !defined(OS_MACOSX)
    118 // static
    119 bool BookmarkNodeData::ClipboardContainsBookmarks() {
    120   return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
    121       ui::Clipboard::GetFormatType(kClipboardFormatString),
    122       ui::CLIPBOARD_TYPE_COPY_PASTE);
    123 }
    124 #endif
    125 
    126 bool BookmarkNodeData::ReadFromVector(
    127     const std::vector<const BookmarkNode*>& nodes) {
    128   Clear();
    129 
    130   if (nodes.empty())
    131     return false;
    132 
    133   for (size_t i = 0; i < nodes.size(); ++i)
    134     elements.push_back(Element(nodes[i]));
    135 
    136   return true;
    137 }
    138 
    139 bool BookmarkNodeData::ReadFromTuple(const GURL& url, const base::string16& title) {
    140   Clear();
    141 
    142   if (!url.is_valid())
    143     return false;
    144 
    145   Element element;
    146   element.title = title;
    147   element.url = url;
    148   element.is_url = true;
    149 
    150   elements.push_back(element);
    151 
    152   return true;
    153 }
    154 
    155 #if !defined(OS_MACOSX)
    156 void BookmarkNodeData::WriteToClipboard(ui::ClipboardType type) {
    157   DCHECK_EQ(type, ui::CLIPBOARD_TYPE_COPY_PASTE);
    158   ui::ScopedClipboardWriter scw(ui::Clipboard::GetForCurrentThread(),
    159                                 ui::CLIPBOARD_TYPE_COPY_PASTE);
    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(UTF8ToUTF16(url));
    179   }
    180 
    181   Pickle pickle;
    182   WriteToPickle(NULL, &pickle);
    183   scw.WritePickledData(pickle,
    184                        ui::Clipboard::GetFormatType(kClipboardFormatString));
    185 }
    186 
    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(), 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 
    218 void BookmarkNodeData::WriteToPickle(Profile* profile, Pickle* pickle) const {
    219   base::FilePath path = profile ? profile->GetPath() : base::FilePath();
    220   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 
    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 
    245 std::vector<const BookmarkNode*> BookmarkNodeData::GetNodes(
    246     Profile* profile) const {
    247   std::vector<const BookmarkNode*> nodes;
    248 
    249   if (!IsFromProfile(profile))
    250     return nodes;
    251 
    252   for (size_t i = 0; i < elements.size(); ++i) {
    253     const BookmarkNode* node = BookmarkModelFactory::GetForProfile(
    254         profile)->GetNodeByID(elements[i].id_);
    255     if (!node) {
    256       nodes.clear();
    257       return nodes;
    258     }
    259     nodes.push_back(node);
    260   }
    261   return nodes;
    262 }
    263 
    264 const BookmarkNode* BookmarkNodeData::GetFirstNode(Profile* profile) const {
    265   std::vector<const BookmarkNode*> nodes = GetNodes(profile);
    266   return nodes.size() == 1 ? nodes[0] : NULL;
    267 }
    268 
    269 void BookmarkNodeData::Clear() {
    270   profile_path_.clear();
    271   elements.clear();
    272 }
    273 
    274 void BookmarkNodeData::SetOriginatingProfile(Profile* profile) {
    275   DCHECK(profile_path_.empty());
    276 
    277   if (profile)
    278     profile_path_ = profile->GetPath();
    279 }
    280 
    281 bool BookmarkNodeData::IsFromProfile(Profile* profile) const {
    282   // An empty path means the data is not associated with any profile.
    283   return !profile_path_.empty() && profile_path_ == profile->GetPath();
    284 }
    285