diff options
Diffstat (limited to 'chrome/browser/extensions/extension_bookmarks_module.cc')
-rw-r--r-- | chrome/browser/extensions/extension_bookmarks_module.cc | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/chrome/browser/extensions/extension_bookmarks_module.cc b/chrome/browser/extensions/extension_bookmarks_module.cc new file mode 100644 index 0000000..aa720ca --- /dev/null +++ b/chrome/browser/extensions/extension_bookmarks_module.cc @@ -0,0 +1,325 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_bookmarks_module.h" + +#include "chrome/browser/bookmarks/bookmark_codec.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/bookmarks/bookmark_utils.h" +#include "chrome/browser/profile.h" + +namespace { +// keys +const wchar_t* kIdKey = L"id"; +const wchar_t* kIndexKey = L"index"; +const wchar_t* kParentIdKey = L"parentId"; +const wchar_t* kUrlKey = L"url"; +const wchar_t* kTitleKey = L"title"; +const wchar_t* kChildrenIdsKey = L"childrenIds"; +const wchar_t* kChildrenKey = L"childrenIds"; +const wchar_t* kRecursiveKey = L"recursive"; + +// errors +const char* kNoNodeError = "Can't find bookmark for id."; +const char* kNoParentError = "Can't find parent bookmark for id."; +const char* kFolderNotEmptyError = + "Can't remove non-empty folder (use recursive to force)."; +const char* kInvalidIndexError = "Index out of bounds."; +const char* kInvalidUrlError = "Invalid URL."; +const char* kModifySpecialError = "Can't modify the root bookmark folders."; +}; + +// Helper functions. +class ExtensionBookmarks { + public: + // Convert |node| into a JSON value + static DictionaryValue* GetNodeDictionary(BookmarkNode* node, bool recurse) { + DictionaryValue* dict = new DictionaryValue(); + dict->SetInteger(kIdKey, node->id()); + + BookmarkNode* parent = node->GetParent(); + if (parent) + dict->SetInteger(kParentIdKey, parent->id()); + + if (!node->is_folder()) + dict->SetString(kUrlKey, node->GetURL().spec()); + + dict->SetString(kTitleKey, node->GetTitle()); + + int childCount = node->GetChildCount(); + ListValue* children = new ListValue(); + for (int i = 0; i < childCount; ++i) { + BookmarkNode* child = node->GetChild(i); + if (recurse) { + DictionaryValue* dict = GetNodeDictionary(child, true); + children->Append(dict); + } else { + Value* child_id = new FundamentalValue(child->id()); + children->Append(child_id); + } + } + if (recurse) + dict->Set(kChildrenKey, children); + else + dict->Set(kChildrenIdsKey, children); + return dict; + } + + // Add a JSON representation of |node| to the JSON |list|. + static void AddNode(BookmarkNode* node, ListValue* list, bool recurse) { + DictionaryValue* dict = GetNodeDictionary(node, recurse); + list->Append(dict); + } + + private: + ExtensionBookmarks(); +}; + +// TODO(erikkay): add a recursive version +bool GetBookmarksFunction::RunImpl() { + // TODO(erikkay): the JSON schema doesn't support the TYPE_INTEGER + // variant yet. + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_LIST) || + args_->IsType(Value::TYPE_INTEGER) || + args_->IsType(Value::TYPE_NULL)); + BookmarkModel* model = profile()->GetBookmarkModel(); + scoped_ptr<ListValue> json(new ListValue()); + if (args_->IsType(Value::TYPE_INTEGER)) { + int id; + EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&id)); + BookmarkNode* node = model->GetNodeByID(id); + if (!node) { + error_ = kNoNodeError; + return false; + } + ExtensionBookmarks::AddNode(node, json.get(), false); + } else { + ListValue* ids = NULL; + size_t count = 0; + if (args_->IsType(Value::TYPE_LIST)) { + ids = static_cast<ListValue*>(args_); + count = ids->GetSize(); + } + if (count == 0) { + // If no ids are passed in, then we default to returning the root node. + BookmarkNode* node = model->root_node(); + ExtensionBookmarks::AddNode(node, json.get(), false); + } else { + for (size_t i = 0; i < count; ++i) { + int id = 0; + EXTENSION_FUNCTION_VALIDATE(ids->GetInteger(i, &id)); + BookmarkNode* node = model->GetNodeByID(id); + if (!node) { + error_ = kNoNodeError; + return false; + } else { + ExtensionBookmarks::AddNode(node, json.get(), false); + } + } + if (error_.size() && json->GetSize() == 0) { + return false; + } + } + } + + result_.reset(json.release()); + return true; +} + +bool SearchBookmarksFunction::RunImpl() { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_STRING)); + + std::wstring query; + EXTENSION_FUNCTION_VALIDATE(args_->GetAsString(&query)); + + BookmarkModel* model = profile()->GetBookmarkModel(); + ListValue* json = new ListValue(); + std::vector<BookmarkNode*> nodes; + bookmark_utils::GetBookmarksContainingText(model, query, 50, &nodes); + std::vector<BookmarkNode*>::iterator i = nodes.begin(); + for (; i != nodes.end(); ++i) { + BookmarkNode* node = *i; + ExtensionBookmarks::AddNode(node, json, false); + } + + result_.reset(json); + return true; +} + +bool RemoveBookmarkFunction::RunImpl() { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); + DictionaryValue* json = static_cast<DictionaryValue*>(args_); + + // TODO(erikkay): it would be cool to take a list here as well. + int id; + EXTENSION_FUNCTION_VALIDATE(json->GetInteger(kIdKey, &id)); + + bool recursive = false; + json->GetBoolean(kRecursiveKey, &recursive); // optional + + BookmarkModel* model = profile()->GetBookmarkModel(); + BookmarkNode* node = model->GetNodeByID(id); + if (!node) { + error_ = kNoNodeError; + return false; + } + if (node == model->root_node() || + node == model->other_node() || + node == model->GetBookmarkBarNode()) { + error_ = kModifySpecialError; + return false; + } + if (node->is_folder() && node->GetChildCount() > 0 && !recursive) { + error_ = kFolderNotEmptyError; + return false; + } + + BookmarkNode* parent = node->GetParent(); + if (!parent) { + error_ = kNoParentError; + return false; + } + int index = parent->IndexOfChild(node); + model->Remove(parent, index); + return true; +} + +bool CreateBookmarkFunction::RunImpl() { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); + DictionaryValue* json = static_cast<DictionaryValue*>(args_); + + BookmarkModel* model = profile()->GetBookmarkModel(); + int parentId; + if (!json->HasKey(kParentIdKey)) { // optional, default to "other bookmarks" + parentId = model->other_node()->id(); + } else { + EXTENSION_FUNCTION_VALIDATE(json->GetInteger(kParentIdKey, &parentId)); + } + BookmarkNode* parent = model->GetNodeByID(parentId); + if (!parent) { + error_ = kNoParentError; + return false; + } + if (parent->GetParent() == NULL) { // can't create children of the root + error_ = kNoParentError; + return false; + } + + int index; + if (!json->HasKey(kIndexKey)) { // optional (defaults to end) + index = parent->GetChildCount(); + } else { + EXTENSION_FUNCTION_VALIDATE(json->GetInteger(kIndexKey, &index)); + if (index > parent->GetChildCount() || index < 0) { + error_ = kInvalidIndexError; + return false; + } + } + + std::wstring title; + json->GetString(kTitleKey, &title); // optional + std::string url_string; + json->GetString(kUrlKey, &url_string); // optional + GURL url(url_string); + if (!url.is_empty() && !url.is_valid()) { + error_ = kInvalidUrlError; + return false; + } + + BookmarkNode* node; + if (url_string.length()) + node = model->AddURL(parent, index, title, url); + else + node = model->AddGroup(parent, index, title); + DCHECK(node); + if (!node) { + error_ = kNoNodeError; + return false; + } + + DictionaryValue* ret = ExtensionBookmarks::GetNodeDictionary(node, false); + result_.reset(ret); + + return true; +} + +bool MoveBookmarkFunction::RunImpl() { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); + DictionaryValue* json = static_cast<DictionaryValue*>(args_); + + // TODO(erikkay) it would be cool if this could be a list of ids as well + int id = 0; + EXTENSION_FUNCTION_VALIDATE(json->GetInteger(kIdKey, &id)); + + BookmarkModel* model = profile()->GetBookmarkModel(); + BookmarkNode* node = model->GetNodeByID(id); + if (!node) { + error_ = kNoNodeError; + return false; + } + if (node == model->root_node() || + node == model->other_node() || + node == model->GetBookmarkBarNode()) { + error_ = kModifySpecialError; + return false; + } + + BookmarkNode* parent; + if (!json->HasKey(kParentIdKey)) { // optional, defaults to current parent + parent = node->GetParent(); + } else { + int parentId; + EXTENSION_FUNCTION_VALIDATE(json->GetInteger(kParentIdKey, &parentId)); + parent = model->GetNodeByID(parentId); + } + if (!parent) { + error_ = kNoParentError; + // TODO(erikkay) return an error message + return false; + } + if (parent == model->root_node()) { + error_ = kModifySpecialError; + return false; + } + + int index; + if (json->HasKey(kIndexKey)) { // optional (defaults to end) + EXTENSION_FUNCTION_VALIDATE(json->GetInteger(kIndexKey, &index)); + if (index > parent->GetChildCount() || index < 0) { + error_ = kInvalidIndexError; + return false; + } + } else { + index = parent->GetChildCount(); + } + + model->Move(node, parent, index); + return true; +} + +bool SetBookmarkTitleFunction::RunImpl() { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); + DictionaryValue* json = static_cast<DictionaryValue*>(args_); + + std::wstring title; + json->GetString(kTitleKey, &title); // optional (empty is clear) + + BookmarkModel* model = profile()->GetBookmarkModel(); + int id = 0; + EXTENSION_FUNCTION_VALIDATE(json->GetInteger(kIdKey, &id)); + BookmarkNode* node = model->GetNodeByID(id); + if (!node) { + error_ = kNoNodeError; + return false; + } + if (node == model->root_node() || + node == model->other_node() || + node == model->GetBookmarkBarNode()) { + error_ = kModifySpecialError; + return false; + } + model->SetTitle(node, title); + return true; +} + |