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 const char* BookmarkNodeData::kClipboardFormatString =
     17     "chromium/x-bookmark-entries";
     18 
     19 BookmarkNodeData::Element::Element() : is_url(false), id_(0) {
     20 }
     21 
     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 
     35 BookmarkNodeData::Element::~Element() {
     36 }
     37 
     38 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 
     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 
    100 BookmarkNodeData::BookmarkNodeData() {
    101 }
    102 
    103 BookmarkNodeData::BookmarkNodeData(const BookmarkNode* node) {
    104   elements.push_back(Element(node));
    105 }
    106 
    107 BookmarkNodeData::BookmarkNodeData(
    108     const std::vector<const BookmarkNode*>& nodes) {
    109   ReadFromVector(nodes);
    110 }
    111 
    112 BookmarkNodeData::~BookmarkNodeData() {
    113 }
    114 
    115 #if !defined(OS_MACOSX)
    116 // static
    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 
    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 
    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)
    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 
    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 
    218 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 
    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     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 
    264 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 
    271 void BookmarkNodeData::Clear() {
    272   profile_path_.clear();
    273   elements.clear();
    274 }
    275 
    276 void BookmarkNodeData::SetOriginatingProfilePath(
    277     const base::FilePath& profile_path) {
    278   DCHECK(profile_path_.empty());
    279   profile_path_ = profile_path;
    280 }
    281 
    282 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