extension_bookmark_manager_api.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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 "chrome/browser/extensions/extension_bookmark_manager_api.h" 6 7#include <vector> 8 9#include "app/l10n_util.h" 10#include "base/json/json_writer.h" 11#include "base/string_number_conversions.h" 12#include "base/values.h" 13#include "chrome/browser/bookmarks/bookmark_drag_data.h" 14#include "chrome/browser/bookmarks/bookmark_model.h" 15#include "chrome/browser/bookmarks/bookmark_utils.h" 16#include "chrome/browser/dom_ui/chrome_url_data_manager.h" 17#include "chrome/browser/extensions/extension_bookmark_helpers.h" 18#include "chrome/browser/extensions/extension_bookmarks_module_constants.h" 19#include "chrome/browser/extensions/extension_dom_ui.h" 20#include "chrome/browser/extensions/extension_message_service.h" 21#include "chrome/browser/profile.h" 22#include "chrome/browser/renderer_host/render_view_host.h" 23#include "chrome/browser/tab_contents/tab_contents.h" 24#include "grit/generated_resources.h" 25 26namespace keys = extension_bookmarks_module_constants; 27 28namespace { 29 30// Returns a single bookmark node from the argument ID. 31// This returns NULL in case of failure. 32const BookmarkNode* GetNodeFromArguments(BookmarkModel* model, 33 const ListValue* args) { 34 std::string id_string; 35 if (!args->GetString(0, &id_string)) 36 return NULL; 37 int64 id; 38 if (!base::StringToInt64(id_string, &id)) 39 return NULL; 40 return model->GetNodeByID(id); 41} 42 43// Gets a vector of bookmark nodes from the argument list of IDs. 44// This returns false in the case of failure. 45bool GetNodesFromArguments(BookmarkModel* model, const ListValue* args, 46 std::vector<const BookmarkNode*>* nodes) { 47 48 ListValue* ids; 49 if (!args->GetList(0, &ids)) 50 return false; 51 52 size_t count = ids->GetSize(); 53 if (count == 0) 54 return false; 55 56 for (size_t i = 0; i < count; ++i) { 57 std::string id_string; 58 if (!ids->GetString(i, &id_string)) 59 return false; 60 int64 id; 61 if (!base::StringToInt64(id_string, &id)) 62 return false; 63 const BookmarkNode* node = model->GetNodeByID(id); 64 if (!node) 65 return false; 66 nodes->push_back(node); 67 } 68 69 return true; 70} 71 72// Recursively adds a node to a list. This is by used |BookmarkDragDataToJSON| 73// when the data comes from the current profile. In this case we have a 74// BookmarkNode since we got the data from the current profile. 75void AddNodeToList(ListValue* list, const BookmarkNode& node) { 76 DictionaryValue* dict = new DictionaryValue(); 77 78 // Add id and parentId so we can associate the data with existing nodes on the 79 // client side. 80 std::string id_string = base::Int64ToString(node.id()); 81 dict->SetString(keys::kIdKey, id_string); 82 83 std::string parent_id_string = base::Int64ToString(node.GetParent()->id()); 84 dict->SetString(keys::kParentIdKey, parent_id_string); 85 86 if (node.is_url()) 87 dict->SetString(keys::kUrlKey, node.GetURL().spec()); 88 89 dict->SetString(keys::kTitleKey, node.GetTitle()); 90 91 ListValue* children = new ListValue(); 92 for (int i = 0; i < node.GetChildCount(); ++i) 93 AddNodeToList(children, *node.GetChild(i)); 94 dict->Set(keys::kChildrenKey, children); 95 96 list->Append(dict); 97} 98 99// Recursively adds an element to a list. This is by used 100// |BookmarkDragDataToJSON| when the data comes from a different profile. When 101// the data comes from a different profile we do not have any IDs or parent IDs. 102void AddElementToList(ListValue* list, 103 const BookmarkDragData::Element& element) { 104 DictionaryValue* dict = new DictionaryValue(); 105 106 if (element.is_url) 107 dict->SetString(keys::kUrlKey, element.url.spec()); 108 109 dict->SetString(keys::kTitleKey, element.title); 110 111 ListValue* children = new ListValue(); 112 for (size_t i = 0; i < element.children.size(); ++i) 113 AddElementToList(children, element.children[i]); 114 dict->Set(keys::kChildrenKey, children); 115 116 list->Append(dict); 117} 118 119// Builds the JSON structure based on the BookmarksDragData. 120void BookmarkDragDataToJSON(Profile* profile, const BookmarkDragData& data, 121 ListValue* args) { 122 bool same_profile = data.IsFromProfile(profile); 123 DictionaryValue* value = new DictionaryValue(); 124 value->SetBoolean(keys::kSameProfileKey, same_profile); 125 126 ListValue* list = new ListValue(); 127 if (same_profile) { 128 std::vector<const BookmarkNode*> nodes = data.GetNodes(profile); 129 for (size_t i = 0; i < nodes.size(); ++i) 130 AddNodeToList(list, *nodes[i]); 131 } else { 132 // We do not have an node IDs when the data comes from a different profile. 133 std::vector<BookmarkDragData::Element> elements = data.elements; 134 for (size_t i = 0; i < elements.size(); ++i) 135 AddElementToList(list, elements[i]); 136 } 137 value->Set(keys::kElementsKey, list); 138 139 args->Append(value); 140} 141 142} // namespace 143 144ExtensionBookmarkManagerEventRouter::ExtensionBookmarkManagerEventRouter( 145 Profile* profile, TabContents* tab_contents) 146 : profile_(profile), 147 tab_contents_(tab_contents) { 148 tab_contents_->SetBookmarkDragDelegate(this); 149} 150 151ExtensionBookmarkManagerEventRouter::~ExtensionBookmarkManagerEventRouter() { 152 if (tab_contents_->GetBookmarkDragDelegate() == this) 153 tab_contents_->SetBookmarkDragDelegate(NULL); 154} 155 156void ExtensionBookmarkManagerEventRouter::DispatchEvent(const char* event_name, 157 const ListValue* args) { 158 if (!profile_->GetExtensionMessageService()) 159 return; 160 161 std::string json_args; 162 base::JSONWriter::Write(args, false, &json_args); 163 profile_->GetExtensionMessageService()->DispatchEventToRenderers( 164 event_name, json_args, profile_, GURL()); 165} 166 167void ExtensionBookmarkManagerEventRouter::DispatchDragEvent( 168 const BookmarkDragData& data, const char* event_name) { 169 if (data.size() == 0) 170 return; 171 172 ListValue args; 173 BookmarkDragDataToJSON(profile_, data, &args); 174 DispatchEvent(event_name, &args); 175} 176 177void ExtensionBookmarkManagerEventRouter::OnDragEnter( 178 const BookmarkDragData& data) { 179 DispatchDragEvent(data, keys::kOnBookmarkDragEnter); 180} 181 182void ExtensionBookmarkManagerEventRouter::OnDragOver( 183 const BookmarkDragData& data) { 184 // Intentionally empty since these events happens too often and floods the 185 // message queue. We do not need this event for the bookmark manager anyway. 186} 187 188void ExtensionBookmarkManagerEventRouter::OnDragLeave( 189 const BookmarkDragData& data) { 190 DispatchDragEvent(data, keys::kOnBookmarkDragLeave); 191} 192 193void ExtensionBookmarkManagerEventRouter::OnDrop( 194 const BookmarkDragData& data) { 195 DispatchDragEvent(data, keys::kOnBookmarkDrop); 196 197 // Make a copy that is owned by this instance. 198 ClearBookmarkDragData(); 199 bookmark_drag_data_ = data; 200} 201 202const BookmarkDragData* 203ExtensionBookmarkManagerEventRouter::GetBookmarkDragData() { 204 if (bookmark_drag_data_.is_valid()) 205 return &bookmark_drag_data_; 206 return NULL; 207} 208 209void ExtensionBookmarkManagerEventRouter::ClearBookmarkDragData() { 210 bookmark_drag_data_.Clear(); 211} 212 213bool ClipboardBookmarkManagerFunction::CopyOrCut(bool cut) { 214 BookmarkModel* model = profile()->GetBookmarkModel(); 215 std::vector<const BookmarkNode*> nodes; 216 EXTENSION_FUNCTION_VALIDATE(GetNodesFromArguments(model, args_.get(), 217 &nodes)); 218 bookmark_utils::CopyToClipboard(model, nodes, cut); 219 return true; 220} 221 222bool CopyBookmarkManagerFunction::RunImpl() { 223 return CopyOrCut(false); 224} 225 226bool CutBookmarkManagerFunction::RunImpl() { 227 return CopyOrCut(true); 228} 229 230bool PasteBookmarkManagerFunction::RunImpl() { 231 BookmarkModel* model = profile()->GetBookmarkModel(); 232 const BookmarkNode* parent_node = GetNodeFromArguments(model, args_.get()); 233 if (!parent_node) { 234 error_ = keys::kNoParentError; 235 return false; 236 } 237 bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node); 238 if (!can_paste) 239 return false; 240 bookmark_utils::PasteFromClipboard(model, parent_node, -1); 241 return true; 242} 243 244bool CanPasteBookmarkManagerFunction::RunImpl() { 245 BookmarkModel* model = profile()->GetBookmarkModel(); 246 const BookmarkNode* parent_node = GetNodeFromArguments(model, args_.get()); 247 if (!parent_node) { 248 error_ = keys::kNoParentError; 249 return false; 250 } 251 bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node); 252 result_.reset(Value::CreateBooleanValue(can_paste)); 253 SendResponse(true); 254 return true; 255} 256 257bool SortChildrenBookmarkManagerFunction::RunImpl() { 258 BookmarkModel* model = profile()->GetBookmarkModel(); 259 const BookmarkNode* parent_node = GetNodeFromArguments(model, args_.get()); 260 if (!parent_node) { 261 error_ = keys::kNoParentError; 262 return false; 263 } 264 model->SortChildren(parent_node); 265 return true; 266} 267 268bool BookmarkManagerGetStringsFunction::RunImpl() { 269 DictionaryValue* localized_strings = new DictionaryValue(); 270 271 localized_strings->SetString("title", 272 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TITLE)); 273 localized_strings->SetString("search_button", 274 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH_BUTTON)); 275 localized_strings->SetString("show_in_folder", 276 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER)); 277 localized_strings->SetString("sort", 278 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SORT)); 279 localized_strings->SetString("organize_menu", 280 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU)); 281 localized_strings->SetString("tools_menu", 282 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TOOLS_MENU)); 283 localized_strings->SetString("import_menu", 284 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_IMPORT_MENU)); 285 localized_strings->SetString("export_menu", 286 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_EXPORT_MENU)); 287 localized_strings->SetString("rename_folder", 288 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_RENAME_FOLDER)); 289 localized_strings->SetString("edit", 290 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_EDIT)); 291 localized_strings->SetString("should_open_all", 292 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL)); 293 localized_strings->SetString("open_incognito", 294 l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_INCOGNITO)); 295 localized_strings->SetString("open_in_new_tab", 296 l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_IN_NEW_TAB)); 297 localized_strings->SetString("open_in_new_window", 298 l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_IN_NEW_WINDOW)); 299 localized_strings->SetString("add_new_bookmark", 300 l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK)); 301 localized_strings->SetString("new_folder", 302 l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_NEW_FOLDER)); 303 localized_strings->SetString("open_all", 304 l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_ALL)); 305 localized_strings->SetString("open_all_new_window", 306 l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW)); 307 localized_strings->SetString("open_all_incognito", 308 l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO)); 309 localized_strings->SetString("remove", 310 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_REMOVE)); 311 localized_strings->SetString("copy", 312 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_COPY)); 313 localized_strings->SetString("cut", 314 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_CUT)); 315 localized_strings->SetString("paste", 316 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PASTE)); 317 localized_strings->SetString("delete", 318 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_DELETE)); 319 localized_strings->SetString("new_folder_name", 320 l10n_util::GetStringUTF16(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME)); 321 localized_strings->SetString("name_input_placeholder", 322 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER)); 323 localized_strings->SetString("url_input_placeholder", 324 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER)); 325 localized_strings->SetString("invalid_url", 326 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_INVALID_URL)); 327 localized_strings->SetString("recent", 328 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_RECENT)); 329 localized_strings->SetString("search", 330 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH)); 331 332 ChromeURLDataManager::DataSource::SetFontAndTextDirection(localized_strings); 333 334 result_.reset(localized_strings); 335 SendResponse(true); 336 return true; 337} 338 339bool StartDragBookmarkManagerFunction::RunImpl() { 340 BookmarkModel* model = profile()->GetBookmarkModel(); 341 std::vector<const BookmarkNode*> nodes; 342 EXTENSION_FUNCTION_VALIDATE( 343 GetNodesFromArguments(model, args_.get(), &nodes)); 344 345 if (dispatcher()->render_view_host()->delegate()->GetRenderViewType() == 346 ViewType::TAB_CONTENTS) { 347 ExtensionDOMUI* dom_ui = 348 static_cast<ExtensionDOMUI*>(dispatcher()->delegate()); 349 bookmark_utils::DragBookmarks( 350 profile(), nodes, dom_ui->tab_contents()->GetNativeView()); 351 352 return true; 353 } else { 354 NOTREACHED(); 355 return false; 356 } 357} 358 359bool DropBookmarkManagerFunction::RunImpl() { 360 BookmarkModel* model = profile()->GetBookmarkModel(); 361 362 int64 id; 363 std::string id_string; 364 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id_string)); 365 366 if (!base::StringToInt64(id_string, &id)) { 367 error_ = keys::kInvalidIdError; 368 return false; 369 } 370 371 const BookmarkNode* drop_parent = model->GetNodeByID(id); 372 if (!drop_parent) { 373 error_ = keys::kNoParentError; 374 return false; 375 } 376 377 int drop_index; 378 if (args_->GetSize() == 2) 379 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(1, &drop_index)); 380 else 381 drop_index = drop_parent->GetChildCount(); 382 383 if (dispatcher()->render_view_host()->delegate()->GetRenderViewType() == 384 ViewType::TAB_CONTENTS) { 385 ExtensionDOMUI* dom_ui = 386 static_cast<ExtensionDOMUI*>(dispatcher()->delegate()); 387 ExtensionBookmarkManagerEventRouter* router = 388 dom_ui->extension_bookmark_manager_event_router(); 389 390 DCHECK(router); 391 const BookmarkDragData* drag_data = router->GetBookmarkDragData(); 392 if (drag_data == NULL) { 393 NOTREACHED() <<"Somehow we're dropping null bookmark data"; 394 return false; 395 } 396 bookmark_utils::PerformBookmarkDrop(profile(), 397 *drag_data, 398 drop_parent, drop_index); 399 400 router->ClearBookmarkDragData(); 401 SendResponse(true); 402 return true; 403 } else { 404 NOTREACHED(); 405 return false; 406 } 407} 408 409bool GetSubtreeBookmarkManagerFunction::RunImpl() { 410 BookmarkModel* model = profile()->GetBookmarkModel(); 411 const BookmarkNode* node; 412 int64 id; 413 std::string id_string; 414 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id_string)); 415 bool folders_only; 416 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &folders_only)); 417 if (id_string == "") { 418 node = model->root_node(); 419 } else { 420 if (!base::StringToInt64(id_string, &id)) { 421 error_ = keys::kInvalidIdError; 422 return false; 423 } 424 node = model->GetNodeByID(id); 425 } 426 if (!node) { 427 error_ = keys::kNoNodeError; 428 return false; 429 } 430 scoped_ptr<ListValue> json(new ListValue()); 431 if (folders_only) { 432 extension_bookmark_helpers::AddNodeFoldersOnly(node, 433 json.get(), 434 true); 435 } else { 436 extension_bookmark_helpers::AddNode(node, json.get(), true); 437 } 438 result_.reset(json.release()); 439 return true; 440} 441