15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 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)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <math.h>  // For floor()
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
1246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/browser/bookmarks/chrome_bookmark_client.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/api/bookmarks.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_model.h"
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_utils.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace keys = bookmark_api_constants;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using api::bookmarks::BookmarkTreeNode;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace bookmark_api_helpers {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void AddNodeHelper(ChromeBookmarkClient* client,
2846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   const BookmarkNode* node,
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   std::vector<linked_ptr<BookmarkTreeNode> >* nodes,
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   bool recurse,
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   bool only_folders) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->IsVisible()) {
3346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    linked_ptr<BookmarkTreeNode> new_node(GetBookmarkTreeNode(client,
3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                                              node,
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                              recurse,
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                              only_folders));
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nodes->push_back(new_node);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)BookmarkTreeNode* GetBookmarkTreeNode(ChromeBookmarkClient* client,
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                      const BookmarkNode* node,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      bool recurse,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      bool only_folders) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkTreeNode* bookmark_tree_node = new BookmarkTreeNode;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_tree_node->id = base::Int64ToString(node->id());
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* parent = node->parent();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_tree_node->parent_id.reset(new std::string(
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Int64ToString(parent->id())));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_tree_node->index.reset(new int(parent->GetIndexOf(node)));
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node->is_folder()) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_tree_node->url.reset(new std::string(node->url().spec()));
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Javascript Date wants milliseconds since the epoch, ToDoubleT is seconds.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time t = node->date_folder_modified();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!t.is_null()) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_tree_node->date_group_modified.reset(
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new double(floor(t.ToDoubleT() * 1000)));
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bookmark_tree_node->title = base::UTF16ToUTF8(node->GetTitle());
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node->date_added().is_null()) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Javascript Date wants milliseconds since the epoch, ToDoubleT is seconds.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_tree_node->date_added.reset(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new double(floor(node->date_added().ToDoubleT() * 1000)));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (client->IsDescendantOfManagedNode(node))
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    bookmark_tree_node->unmodifiable = BookmarkTreeNode::UNMODIFIABLE_MANAGED;
7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (recurse && node->is_folder()) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<linked_ptr<BookmarkTreeNode> > children;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < node->child_count(); ++i) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const BookmarkNode* child = node->GetChild(i);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (child->IsVisible() && (!only_folders || child->is_folder())) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        linked_ptr<BookmarkTreeNode> child_node(
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            GetBookmarkTreeNode(client, child, true, only_folders));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        children.push_back(child_node);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_tree_node->children.reset(
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new std::vector<linked_ptr<BookmarkTreeNode> >(children));
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bookmark_tree_node;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void AddNode(ChromeBookmarkClient* client,
9646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)             const BookmarkNode* node,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             std::vector<linked_ptr<BookmarkTreeNode> >* nodes,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             bool recurse) {
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return AddNodeHelper(client, node, nodes, recurse, false);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void AddNodeFoldersOnly(ChromeBookmarkClient* client,
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        const BookmarkNode* node,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::vector<linked_ptr<BookmarkTreeNode> >* nodes,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        bool recurse) {
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return AddNodeHelper(client, node, nodes, recurse, true);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool RemoveNode(BookmarkModel* model,
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                ChromeBookmarkClient* client,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                int64 id,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                bool recursive,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                std::string* error) {
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const BookmarkNode* node = bookmarks::GetBookmarkNodeByID(model, id);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error = keys::kNoNodeError;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model->is_permanent_node(node)) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error = keys::kModifySpecialError;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (client->IsDescendantOfManagedNode(node)) {
12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    *error = keys::kModifyManagedError;
12546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
12646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_folder() && !node->empty() && !recursive) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error = keys::kFolderNotEmptyError;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* parent = node->parent();
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model->Remove(parent, parent->GetIndexOf(node));
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void GetMetaInfo(const BookmarkNode& node,
1386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 base::DictionaryValue* id_to_meta_info_map) {
1396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!node.IsVisible())
1406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
1416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const BookmarkNode::MetaInfoMap* meta_info = node.GetMetaInfoMap();
1436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  base::DictionaryValue* value = new base::DictionaryValue();
1446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (meta_info) {
1456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    BookmarkNode::MetaInfoMap::const_iterator itr;
1466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    for (itr = meta_info->begin(); itr != meta_info->end(); ++itr) {
1476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      value->SetStringWithoutPathExpansion(itr->first, itr->second);
1486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
1496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  id_to_meta_info_map->Set(base::Int64ToString(node.id()), value);
1516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (node.is_folder()) {
1536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    for (int i = 0; i < node.child_count(); ++i) {
1546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      GetMetaInfo(*(node.GetChild(i)), id_to_meta_info_map);
1556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
1566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace bookmark_api_helpers
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
161