Home | History | Annotate | Download | only in browser
      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 namespace bookmarks {
     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,
    140                                      const base::string16& title) {
    141   Clear();
    142 
    143   if (!url.is_valid())
    144     return false;
    145 
    146   Element element;
    147   element.title = title;
    148   element.url = url;
    149   element.is_url = true;
    150 
    151   elements.push_back(element);
    152 
    153   return true;
    154 }
    155 
    156 #if !defined(OS_MACOSX)
    157 void BookmarkNodeData::WriteToClipboard(ui::ClipboardType clipboard_type) {
    158   DCHECK(clipboard_type == ui::CLIPBOARD_TYPE_COPY_PASTE ||
    159          clipboard_type == ui::CLIPBOARD_TYPE_SELECTION);
    160   ui::ScopedClipboardWriter scw(clipboard_type);
    161 
    162   // If there is only one element and it is a URL, write the URL to the
    163   // clipboard.
    164   if (elements.size() == 1 && elements[0].is_url) {
    165     const base::string16& title = elements[0].title;
    166     const std::string url = elements[0].url.spec();
    167 
    168     scw.WriteBookmark(title, url);
    169 
    170     // Don't call scw.WriteHyperlink() here, since some rich text editors will
    171     // change fonts when such data is pasted in; besides, most such editors
    172     // auto-linkify at some point anyway.
    173 
    174     // Also write the URL to the clipboard as text so that it can be pasted
    175     // into text fields. We use WriteText instead of WriteURL because we don't
    176     // want to clobber the X clipboard when the user copies out of the omnibox
    177     // on Linux (on Windows and Mac, there is no difference between these
    178     // functions).
    179     scw.WriteText(base::UTF8ToUTF16(url));
    180   }
    181 
    182   Pickle pickle;
    183   WriteToPickle(base::FilePath(), &pickle);
    184   scw.WritePickledData(pickle,
    185                        ui::Clipboard::GetFormatType(kClipboardFormatString));
    186 }
    187 
    188 bool BookmarkNodeData::ReadFromClipboard(ui::ClipboardType type) {
    189   DCHECK_EQ(type, ui::CLIPBOARD_TYPE_COPY_PASTE);
    190   std::string data;
    191   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
    192   clipboard->ReadData(ui::Clipboard::GetFormatType(kClipboardFormatString),
    193                       &data);
    194 
    195   if (!data.empty()) {
    196     Pickle pickle(data.data(), static_cast<int>(data.size()));
    197     if (ReadFromPickle(&pickle))
    198       return true;
    199   }
    200 
    201   base::string16 title;
    202   std::string url;
    203   clipboard->ReadBookmark(&title, &url);
    204   if (!url.empty()) {
    205     Element element;
    206     element.is_url = true;
    207     element.url = GURL(url);
    208     element.title = title;
    209 
    210     elements.clear();
    211     elements.push_back(element);
    212     return true;
    213   }
    214 
    215   return false;
    216 }
    217 #endif
    218 
    219 void BookmarkNodeData::WriteToPickle(const base::FilePath& profile_path,
    220                                      Pickle* pickle) const {
    221   profile_path.WriteToPickle(pickle);
    222   pickle->WriteUInt64(elements.size());
    223 
    224   for (size_t i = 0; i < elements.size(); ++i)
    225     elements[i].WriteToPickle(pickle);
    226 }
    227 
    228 bool BookmarkNodeData::ReadFromPickle(Pickle* pickle) {
    229   PickleIterator data_iterator(*pickle);
    230   uint64 element_count;
    231   if (profile_path_.ReadFromPickle(&data_iterator) &&
    232       pickle->ReadUInt64(&data_iterator, &element_count)) {
    233     std::vector<Element> tmp_elements;
    234     tmp_elements.resize(element_count);
    235     for (uint64 i = 0; i < element_count; ++i) {
    236       if (!tmp_elements[i].ReadFromPickle(pickle, &data_iterator)) {
    237         return false;
    238       }
    239     }
    240     elements.swap(tmp_elements);
    241   }
    242 
    243   return true;
    244 }
    245 
    246 std::vector<const BookmarkNode*> BookmarkNodeData::GetNodes(
    247     BookmarkModel* model,
    248     const base::FilePath& profile_path) const {
    249   std::vector<const BookmarkNode*> nodes;
    250 
    251   if (!IsFromProfilePath(profile_path))
    252     return nodes;
    253 
    254   for (size_t i = 0; i < elements.size(); ++i) {
    255     const BookmarkNode* node = GetBookmarkNodeByID(model, elements[i].id_);
    256     if (!node) {
    257       nodes.clear();
    258       return nodes;
    259     }
    260     nodes.push_back(node);
    261   }
    262   return nodes;
    263 }
    264 
    265 const BookmarkNode* BookmarkNodeData::GetFirstNode(
    266     BookmarkModel* model,
    267     const base::FilePath& profile_path) const {
    268   std::vector<const BookmarkNode*> nodes = GetNodes(model, profile_path);
    269   return nodes.size() == 1 ? nodes[0] : NULL;
    270 }
    271 
    272 void BookmarkNodeData::Clear() {
    273   profile_path_.clear();
    274   elements.clear();
    275 }
    276 
    277 void BookmarkNodeData::SetOriginatingProfilePath(
    278     const base::FilePath& profile_path) {
    279   DCHECK(profile_path_.empty());
    280   profile_path_ = profile_path;
    281 }
    282 
    283 bool BookmarkNodeData::IsFromProfilePath(
    284     const base::FilePath& profile_path) const {
    285   // An empty path means the data is not associated with any profile.
    286   return !profile_path_.empty() && profile_path_ == profile_path;
    287 }
    288 
    289 }  // namespace bookmarks
    290