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"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/api/bookmarks.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace keys = bookmark_api_constants;
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using api::bookmarks::BookmarkTreeNode;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace bookmark_api_helpers {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AddNodeHelper(const BookmarkNode* node,
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   std::vector<linked_ptr<BookmarkTreeNode> >* nodes,
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   bool recurse,
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   bool only_folders) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->IsVisible()) {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    linked_ptr<BookmarkTreeNode> new_node(GetBookmarkTreeNode(node,
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                              recurse,
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                              only_folders));
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nodes->push_back(new_node);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(mwrosen): Remove this function once chrome.bookmarkManagerPrivate is
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// refactored to use the JSON schema compiler.
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AddNodeHelper(const BookmarkNode* node,
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::ListValue* list,
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   bool recurse,
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   bool only_folders) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->IsVisible()) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* dict =
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetNodeDictionary(node, recurse, only_folders);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    list->Append(dict);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkTreeNode* GetBookmarkTreeNode(const BookmarkNode* node,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      bool recurse,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      bool only_folders) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkTreeNode* bookmark_tree_node = new BookmarkTreeNode;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_tree_node->id = base::Int64ToString(node->id());
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* parent = node->parent();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_tree_node->parent_id.reset(new std::string(
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Int64ToString(parent->id())));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_tree_node->index.reset(new int(parent->GetIndexOf(node)));
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node->is_folder()) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_tree_node->url.reset(new std::string(node->url().spec()));
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Javascript Date wants milliseconds since the epoch, ToDoubleT is seconds.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time t = node->date_folder_modified();
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!t.is_null()) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_tree_node->date_group_modified.reset(
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new double(floor(t.ToDoubleT() * 1000)));
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_tree_node->title = UTF16ToUTF8(node->GetTitle());
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node->date_added().is_null()) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Javascript Date wants milliseconds since the epoch, ToDoubleT is seconds.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_tree_node->date_added.reset(
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new double(floor(node->date_added().ToDoubleT() * 1000)));
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (recurse && node->is_folder()) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<linked_ptr<BookmarkTreeNode> > children;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < node->child_count(); ++i) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const BookmarkNode* child = node->GetChild(i);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (child->IsVisible() && (!only_folders || child->is_folder())) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        linked_ptr<BookmarkTreeNode> child_node(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            GetBookmarkTreeNode(child, true, only_folders));
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        children.push_back(child_node);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmark_tree_node->children.reset(
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new std::vector<linked_ptr<BookmarkTreeNode> >(children));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bookmark_tree_node;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::DictionaryValue* GetNodeDictionary(const BookmarkNode* node,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         bool recurse,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         bool only_folders) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString(keys::kIdKey, base::Int64ToString(node->id()));
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* parent = node->parent();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dict->SetString(keys::kParentIdKey, base::Int64ToString(parent->id()));
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dict->SetInteger(keys::kIndexKey, parent->GetIndexOf(node));
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node->is_folder()) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dict->SetString(keys::kUrlKey, node->url().spec());
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Javascript Date wants milliseconds since the epoch, ToDoubleT is seconds.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time t = node->date_folder_modified();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!t.is_null())
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dict->SetDouble(keys::kDateFolderModifiedKey,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      floor(t.ToDoubleT() * 1000));
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString(keys::kTitleKey, node->GetTitle());
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node->date_added().is_null()) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Javascript Date wants milliseconds since the epoch, ToDoubleT is seconds.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dict->SetDouble(keys::kDateAddedKey,
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    floor(node->date_added().ToDoubleT() * 1000));
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (recurse && node->is_folder()) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ListValue* children = new base::ListValue;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < node->child_count(); ++i) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const BookmarkNode* child = node->GetChild(i);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (child->IsVisible() && (!only_folders || child->is_folder())) {
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        base::DictionaryValue* dict =
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            GetNodeDictionary(child, true, only_folders);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        children->Append(dict);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dict->Set(keys::kChildrenKey, children);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AddNode(const BookmarkNode* node,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             std::vector<linked_ptr<BookmarkTreeNode> >* nodes,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             bool recurse) {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return AddNodeHelper(node, nodes, recurse, false);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AddNodeFoldersOnly(const BookmarkNode* node,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::vector<linked_ptr<BookmarkTreeNode> >* nodes,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        bool recurse) {
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return AddNodeHelper(node, nodes, recurse, true);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AddNode(const BookmarkNode* node, base::ListValue* list, bool recurse) {
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return AddNodeHelper(node, list, recurse, false);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AddNodeFoldersOnly(const BookmarkNode* node,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        base::ListValue* list,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        bool recurse) {
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return AddNodeHelper(node, list, recurse, true);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool RemoveNode(BookmarkModel* model,
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                int64 id,
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                bool recursive,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                std::string* error) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = model->GetNodeByID(id);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error = keys::kNoNodeError;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model->is_permanent_node(node)) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error = keys::kModifySpecialError;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_folder() && !node->empty() && !recursive) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error = keys::kFolderNotEmptyError;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* parent = node->parent();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model->Remove(parent, parent->GetIndexOf(node));
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace bookmark_api_helpers
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
192