15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_utils.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/case_conversion.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/string_search.h"
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/metrics/user_metrics_action.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/bookmarks/browser/bookmark_client.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_model.h"
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/common/bookmark_pref_names.h"
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/query_parser/query_parser.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/base/clipboard/clipboard.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/models/tree_node_iterator.h"
270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "url/gurl.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace bookmarks {
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// The maximum length of URL or title returned by the Cleanup functions.
360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst size_t kCleanedUpUrlMaxLength = 1024u;
370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst size_t kCleanedUpTitleMaxLength = 1024u;
380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloneBookmarkNodeImpl(BookmarkModel* model,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const BookmarkNodeData::Element& element,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const BookmarkNode* parent,
423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           int index_to_add_at,
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           bool reset_node_times) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (element.is_url) {
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Time date_added = reset_node_times ? Time::Now() : element.date_added;
460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DCHECK(!date_added.is_null());
470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    model->AddURLWithCreationTimeAndMetaInfo(parent,
490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                             index_to_add_at,
500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                             element.title,
510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                             element.url,
520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                             date_added,
530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                             &element.meta_info_map);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const BookmarkNode* cloned_node = model->AddFolderWithMetaInfo(
560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        parent, index_to_add_at, element.title, &element.meta_info_map);
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!reset_node_times) {
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      DCHECK(!element.date_folder_modified.is_null());
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      model->SetDateFolderModified(cloned_node, element.date_folder_modified);
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < static_cast<int>(element.children.size()); ++i)
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      CloneBookmarkNodeImpl(model, element.children[i], cloned_node, i,
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                            reset_node_times);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Comparison function that compares based on date modified of the two nodes.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MoreRecentlyModified(const BookmarkNode* n1, const BookmarkNode* n2) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return n1->date_folder_modified() > n2->date_folder_modified();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |text| contains each string in |words|. This is used when
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// searching for bookmarks.
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool DoesBookmarkTextContainWords(const base::string16& text,
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  const std::vector<base::string16>& words) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < words.size(); ++i) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!base::i18n::StringSearchIgnoringCaseAndAccents(
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            words[i], text, NULL, NULL)) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |node|s title or url contains the strings in |words|.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |languages| argument is user's accept-language setting to decode IDN.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DoesBookmarkContainWords(const BookmarkNode* node,
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const std::vector<base::string16>& words,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const std::string& languages) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DoesBookmarkTextContainWords(node->GetTitle(), words) ||
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DoesBookmarkTextContainWords(
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::UTF8ToUTF16(node->url().spec()), words) ||
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DoesBookmarkTextContainWords(net::FormatUrl(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          node->url(), languages, net::kFormatUrlOmitNothing,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          net::UnescapeRule::NORMAL, NULL, NULL, NULL), words);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// This is used with a tree iterator to skip subtrees which are not visible.
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool PruneInvisibleFolders(const BookmarkNode* node) {
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return !node->IsVisible();
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This traces parents up to root, determines if node is contained in a
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// selected folder.
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HasSelectedAncestor(BookmarkModel* model,
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         const std::vector<const BookmarkNode*>& selected_nodes,
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         const BookmarkNode* node) {
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!node || model->is_permanent_node(node))
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = 0; i < selected_nodes.size(); ++i)
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (node->id() == selected_nodes[i]->id())
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return HasSelectedAncestor(model, selected_nodes, node->parent());
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst BookmarkNode* GetNodeByID(const BookmarkNode* node, int64 id) {
1200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (node->id() == id)
1210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return node;
1220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (int i = 0, child_count = node->child_count(); i < child_count; ++i) {
1240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const BookmarkNode* result = GetNodeByID(node->GetChild(i), id);
1250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (result)
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return result;
1270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return NULL;
1290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Attempts to shorten a URL safely (i.e., by preventing the end of the URL
1320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// from being in the middle of an escape sequence) to no more than
1330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// kCleanedUpUrlMaxLength characters, returning the result.
1340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochstd::string TruncateUrl(const std::string& url) {
1350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (url.length() <= kCleanedUpUrlMaxLength)
1360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return url;
1370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // If we're in the middle of an escape sequence, truncate just before it.
1390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (url[kCleanedUpUrlMaxLength - 1] == '%')
1400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return url.substr(0, kCleanedUpUrlMaxLength - 1);
1410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (url[kCleanedUpUrlMaxLength - 2] == '%')
1420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return url.substr(0, kCleanedUpUrlMaxLength - 2);
1430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return url.substr(0, kCleanedUpUrlMaxLength);
1450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Returns the URL from the clipboard. If there is no URL an empty URL is
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// returned.
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGURL GetUrlFromClipboard() {
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::string16 url_text;
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if !defined(OS_IOS)
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ui::Clipboard::GetForCurrentThread()->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE,
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                 &url_text);
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return GURL(url_text);
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)QueryFields::QueryFields() {}
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)QueryFields::~QueryFields() {}
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloneBookmarkNode(BookmarkModel* model,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::vector<BookmarkNodeData::Element>& elements,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const BookmarkNode* parent,
1663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                       int index_to_add_at,
1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                       bool reset_node_times) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parent->is_folder() || !model) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (size_t i = 0; i < elements.size(); ++i) {
1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    CloneBookmarkNodeImpl(model, elements[i], parent,
1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          index_to_add_at + static_cast<int>(i),
1753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                          reset_node_times);
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CopyToClipboard(BookmarkModel* model,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const std::vector<const BookmarkNode*>& nodes,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     bool remove_nodes) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (nodes.empty())
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Create array of selected nodes with descendants filtered out.
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<const BookmarkNode*> filtered_nodes;
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < nodes.size(); ++i)
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!HasSelectedAncestor(model, nodes, nodes[i]->parent()))
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      filtered_nodes.push_back(nodes[i]);
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BookmarkNodeData(filtered_nodes).
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      WriteToClipboard(ui::CLIPBOARD_TYPE_COPY_PASTE);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (remove_nodes) {
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ScopedGroupBookmarkActions group_cut(model);
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (size_t i = 0; i < filtered_nodes.size(); ++i) {
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      int index = filtered_nodes[i]->parent()->GetIndexOf(filtered_nodes[i]);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (index > -1)
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        model->Remove(filtered_nodes[i]->parent(), index);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasteFromClipboard(BookmarkModel* model,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const BookmarkNode* parent,
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int index) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parent)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNodeData bookmark_data;
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!bookmark_data.ReadFromClipboard(ui::CLIPBOARD_TYPE_COPY_PASTE)) {
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    GURL url = GetUrlFromClipboard();
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!url.is_valid())
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    BookmarkNode node(url);
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    node.SetTitle(base::ASCIIToUTF16(url.spec()));
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bookmark_data = BookmarkNodeData(&node);
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index == -1)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = parent->child_count();
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ScopedGroupBookmarkActions group_paste(model);
2223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CloneBookmarkNode(model, bookmark_data.elements, parent, index, true);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool CanPasteFromClipboard(BookmarkModel* model, const BookmarkNode* node) {
22646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!node || !model->client()->CanBeEditedByUser(node))
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return (BookmarkNodeData::ClipboardContainsBookmarks() ||
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          GetUrlFromClipboard().is_valid());
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)std::vector<const BookmarkNode*> GetMostRecentlyModifiedUserFolders(
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkModel* model,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t max_count) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const BookmarkNode*> nodes;
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ui::TreeNodeIterator<const BookmarkNode> iterator(
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      model->root_node(), base::Bind(&PruneInvisibleFolders));
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (iterator.has_next()) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* parent = iterator.Next();
24146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!model->client()->CanBeEditedByUser(parent))
24246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (parent->is_folder() && parent->date_folder_modified() > Time()) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (max_count == 0) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        nodes.push_back(parent);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::vector<const BookmarkNode*>::iterator i =
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            std::upper_bound(nodes.begin(), nodes.end(), parent,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             &MoreRecentlyModified);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (nodes.size() < max_count || i != nodes.end()) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          nodes.insert(i, parent);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          while (nodes.size() > max_count)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            nodes.pop_back();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }  // else case, the root node, which we don't care about or imported nodes
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       // (which have a time of 0).
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (nodes.size() < max_count) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add the permanent nodes if there is space. The permanent nodes are the
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // only children of the root_node.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* root_node = model->root_node();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < root_node->child_count(); ++i) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const BookmarkNode* node = root_node->GetChild(i);
26746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (node->IsVisible() && model->client()->CanBeEditedByUser(node) &&
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          std::find(nodes.begin(), nodes.end(), node) == nodes.end()) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        nodes.push_back(node);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (nodes.size() == max_count)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return nodes;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetMostRecentlyAddedEntries(BookmarkModel* model,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 size_t count,
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 std::vector<const BookmarkNode*>* nodes) {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (iterator.has_next()) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* node = iterator.Next();
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (node->is_url()) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<const BookmarkNode*>::iterator insert_position =
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          std::upper_bound(nodes->begin(), nodes->end(), node,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &MoreRecentlyAdded);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (nodes->size() < count || insert_position != nodes->end()) {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        nodes->insert(insert_position, node);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        while (nodes->size() > count)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          nodes->pop_back();
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MoreRecentlyAdded(const BookmarkNode* n1, const BookmarkNode* n2) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return n1->date_added() > n2->date_added();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GetBookmarksMatchingProperties(BookmarkModel* model,
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    const QueryFields& query,
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    size_t max_count,
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    const std::string& languages,
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    std::vector<const BookmarkNode*>* nodes) {
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<base::string16> query_words;
3080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  query_parser::QueryParser parser;
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (query.word_phrase_query) {
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.ParseQueryWords(base::i18n::ToLower(*query.word_phrase_query),
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           &query_words);
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (query_words.empty())
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (iterator.has_next()) {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* node = iterator.Next();
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if ((!query_words.empty() &&
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        !DoesBookmarkContainWords(node, query_words, languages)) ||
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        model->is_permanent_node(node)) {
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (query.url) {
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Check against bare url spec and IDN-decoded url.
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!node->is_url() ||
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          !(base::UTF8ToUTF16(node->url().spec()) == *query.url ||
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            net::FormatUrl(
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                node->url(), languages, net::kFormatUrlOmitNothing,
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                net::UnescapeRule::NORMAL, NULL, NULL, NULL) == *query.url)) {
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        continue;
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (query.title && node->GetTitle() != *query.title)
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    nodes->push_back(node);
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (nodes->size() == max_count)
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registry->RegisterBooleanPref(
345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      prefs::kShowBookmarkBar,
346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      false,
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registry->RegisterBooleanPref(
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      prefs::kEditBookmarksEnabled,
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      true,
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registry->RegisterBooleanPref(
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      prefs::kShowAppsShortcutInBookmarkBar,
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      true,
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  registry->RegisterBooleanPref(
357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      prefs::kShowManagedBookmarksInBookmarkBar,
358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      true,
359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* GetParentForNewNodes(
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* parent,
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<const BookmarkNode*>& selection,
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int* index) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* real_parent = parent;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (selection.size() == 1 && selection[0]->is_folder())
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    real_parent = selection[0];
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (selection.size() == 1 && selection[0]->is_url()) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *index = real_parent->GetIndexOf(selection[0]) + 1;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (*index == 0) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Node doesn't exist in parent, add to end.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *index = real_parent->child_count();
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *index = real_parent->child_count();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return real_parent;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeleteBookmarkFolders(BookmarkModel* model,
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const std::vector<int64>& ids) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the folders that were removed. This has to be done after all the
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // other changes have been committed.
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<int64>::const_iterator iter = ids.begin();
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != ids.end();
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++iter) {
3940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const BookmarkNode* node = GetBookmarkNodeByID(model, *iter);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!node)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* parent = node->parent();
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model->Remove(parent, parent->GetIndexOf(node));
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AddIfNotBookmarked(BookmarkModel* model,
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const GURL& url,
404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        const base::string16& title) {
40546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (IsBookmarkedByUser(model, url))
40646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;  // Nothing to do, a user bookmark with that url already exists.
4075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  model->client()->RecordAction(base::UserMetricsAction("BookmarkAdded"));
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* parent = model->GetParentForNewNodes();
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model->AddURL(parent, parent->child_count(), title, url);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RemoveAllBookmarks(BookmarkModel* model, const GURL& url) {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const BookmarkNode*> bookmarks;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model->GetNodesByURL(url, &bookmarks);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Remove all the user bookmarks.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < bookmarks.size(); ++i) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* node = bookmarks[i];
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index = node->parent()->GetIndexOf(node);
42046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (index > -1 && model->client()->CanBeEditedByUser(node))
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model->Remove(node->parent(), index);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubase::string16 CleanUpUrlForMatching(
4265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const GURL& gurl,
4275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& languages,
4285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    base::OffsetAdjuster::Adjustments* adjustments) {
4295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::OffsetAdjuster::Adjustments tmp_adjustments;
4305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return base::i18n::ToLower(net::FormatUrlWithAdjustments(
4310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      GURL(TruncateUrl(gurl.spec())), languages,
4320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      net::kFormatUrlOmitUsernamePassword,
4330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS,
4345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      NULL, NULL, adjustments ? adjustments : &tmp_adjustments));
4350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
4360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbase::string16 CleanUpTitleForMatching(const base::string16& title) {
4380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return base::i18n::ToLower(title.substr(0u, kCleanedUpTitleMaxLength));
4390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
4400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
44146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool CanAllBeEditedByUser(BookmarkClient* client,
44246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                          const std::vector<const BookmarkNode*>& nodes) {
44346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (size_t i = 0; i < nodes.size(); ++i) {
44446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!client->CanBeEditedByUser(nodes[i]))
44546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return false;
44646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
44746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return true;
44846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
44946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
45046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool IsBookmarkedByUser(BookmarkModel* model, const GURL& url) {
45146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::vector<const BookmarkNode*> nodes;
45246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  model->GetNodesByURL(url, &nodes);
45346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (size_t i = 0; i < nodes.size(); ++i) {
45446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (model->client()->CanBeEditedByUser(nodes[i]))
45546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return true;
45646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
45746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return false;
45846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
45946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst BookmarkNode* GetBookmarkNodeByID(const BookmarkModel* model, int64 id) {
4610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // TODO(sky): TreeNode needs a method that visits all nodes using a predicate.
4620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return GetNodeByID(model->root_node(), id);
4630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
464116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
465116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace bookmarks
466