bookmark_manager_private_api.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright (c) 2012 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/api/bookmark_manager_private/bookmark_manager_private_api.h"
6
7#include <vector>
8
9#include "base/lazy_instance.h"
10#include "base/memory/linked_ptr.h"
11#include "base/prefs/pref_service.h"
12#include "base/strings/string_number_conversions.h"
13#include "base/strings/utf_string_conversions.h"
14#include "base/values.h"
15#include "chrome/browser/bookmarks/bookmark_model_factory.h"
16#include "chrome/browser/bookmarks/bookmark_stats.h"
17#include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h"
18#include "chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.h"
19#include "chrome/browser/extensions/extension_web_ui.h"
20#include "chrome/browser/profiles/profile.h"
21#include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h"
22#include "chrome/browser/undo/bookmark_undo_service.h"
23#include "chrome/browser/undo/bookmark_undo_service_factory.h"
24#include "chrome/common/extensions/api/bookmark_manager_private.h"
25#include "chrome/common/pref_names.h"
26#include "components/bookmarks/browser/bookmark_model.h"
27#include "components/bookmarks/browser/bookmark_node_data.h"
28#include "components/bookmarks/browser/bookmark_utils.h"
29#include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
30#include "components/user_prefs/user_prefs.h"
31#include "content/public/browser/render_view_host.h"
32#include "content/public/browser/web_contents.h"
33#include "content/public/browser/web_ui.h"
34#include "extensions/browser/extension_function_dispatcher.h"
35#include "extensions/browser/view_type_utils.h"
36#include "grit/generated_resources.h"
37#include "ui/base/dragdrop/drag_drop_types.h"
38#include "ui/base/l10n/l10n_util.h"
39#include "ui/base/webui/web_ui_util.h"
40
41namespace extensions {
42
43namespace bookmark_keys = bookmark_api_constants;
44namespace bookmark_manager_private = api::bookmark_manager_private;
45namespace CanPaste = api::bookmark_manager_private::CanPaste;
46namespace Copy = api::bookmark_manager_private::Copy;
47namespace CreateWithMetaInfo =
48    api::bookmark_manager_private::CreateWithMetaInfo;
49namespace Cut = api::bookmark_manager_private::Cut;
50namespace Drop = api::bookmark_manager_private::Drop;
51namespace GetSubtree = api::bookmark_manager_private::GetSubtree;
52namespace GetMetaInfo = api::bookmark_manager_private::GetMetaInfo;
53namespace Paste = api::bookmark_manager_private::Paste;
54namespace RedoInfo = api::bookmark_manager_private::GetRedoInfo;
55namespace RemoveTrees = api::bookmark_manager_private::RemoveTrees;
56namespace SetMetaInfo = api::bookmark_manager_private::SetMetaInfo;
57namespace SortChildren = api::bookmark_manager_private::SortChildren;
58namespace StartDrag = api::bookmark_manager_private::StartDrag;
59namespace UndoInfo = api::bookmark_manager_private::GetUndoInfo;
60namespace UpdateMetaInfo = api::bookmark_manager_private::UpdateMetaInfo;
61
62using content::WebContents;
63
64namespace {
65
66// Returns a single bookmark node from the argument ID.
67// This returns NULL in case of failure.
68const BookmarkNode* GetNodeFromString(BookmarkModel* model,
69                                      const std::string& id_string) {
70  int64 id;
71  if (!base::StringToInt64(id_string, &id))
72    return NULL;
73  return GetBookmarkNodeByID(model, id);
74}
75
76// Gets a vector of bookmark nodes from the argument list of IDs.
77// This returns false in the case of failure.
78bool GetNodesFromVector(BookmarkModel* model,
79                        const std::vector<std::string>& id_strings,
80                        std::vector<const BookmarkNode*>* nodes) {
81
82  if (id_strings.empty())
83    return false;
84
85  for (size_t i = 0; i < id_strings.size(); ++i) {
86    const BookmarkNode* node = GetNodeFromString(model, id_strings[i]);
87    if (!node)
88      return false;
89    nodes->push_back(node);
90  }
91
92  return true;
93}
94
95// Recursively create a bookmark_manager_private::BookmarkNodeDataElement from
96// a bookmark node. This is by used |BookmarkNodeDataToJSON| when the data comes
97// from the current profile. In this case we have a BookmarkNode since we got
98// the data from the current profile.
99linked_ptr<bookmark_manager_private::BookmarkNodeDataElement>
100CreateNodeDataElementFromBookmarkNode(const BookmarkNode& node) {
101  linked_ptr<bookmark_manager_private::BookmarkNodeDataElement> element(
102      new bookmark_manager_private::BookmarkNodeDataElement);
103  // Add id and parentId so we can associate the data with existing nodes on the
104  // client side.
105  element->id.reset(new std::string(base::Int64ToString(node.id())));
106  element->parent_id.reset(
107      new std::string(base::Int64ToString(node.parent()->id())));
108
109  if (node.is_url())
110    element->url.reset(new std::string(node.url().spec()));
111
112  element->title = base::UTF16ToUTF8(node.GetTitle());
113  for (int i = 0; i < node.child_count(); ++i) {
114    element->children.push_back(
115        CreateNodeDataElementFromBookmarkNode(*node.GetChild(i)));
116  }
117
118  return element;
119}
120
121// Recursively create a bookmark_manager_private::BookmarkNodeDataElement from
122// a BookmarkNodeData::Element. This is used by |BookmarkNodeDataToJSON| when
123// the data comes from a different profile. When the data comes from a different
124// profile we do not have any IDs or parent IDs.
125linked_ptr<bookmark_manager_private::BookmarkNodeDataElement>
126CreateApiNodeDataElement(const BookmarkNodeData::Element& element) {
127  linked_ptr<bookmark_manager_private::BookmarkNodeDataElement> node_element(
128      new bookmark_manager_private::BookmarkNodeDataElement);
129
130  if (element.is_url)
131    node_element->url.reset(new std::string(element.url.spec()));
132  node_element->title = base::UTF16ToUTF8(element.title);
133  for (size_t i = 0; i < element.children.size(); ++i) {
134    node_element->children.push_back(
135        CreateApiNodeDataElement(element.children[i]));
136  }
137
138  return node_element;
139}
140
141// Creates a bookmark_manager_private::BookmarkNodeData from a BookmarkNodeData.
142scoped_ptr<bookmark_manager_private::BookmarkNodeData>
143CreateApiBookmarkNodeData(Profile* profile, const BookmarkNodeData& data) {
144  const base::FilePath& profile_path = profile->GetPath();
145
146  scoped_ptr<bookmark_manager_private::BookmarkNodeData> node_data(
147      new bookmark_manager_private::BookmarkNodeData);
148  node_data->same_profile = data.IsFromProfilePath(profile_path);
149
150  if (node_data->same_profile) {
151    std::vector<const BookmarkNode*> nodes = data.GetNodes(
152        BookmarkModelFactory::GetForProfile(profile), profile_path);
153    for (size_t i = 0; i < nodes.size(); ++i) {
154      node_data->elements.push_back(
155          CreateNodeDataElementFromBookmarkNode(*nodes[i]));
156    }
157  } else {
158    // We do not have a node IDs when the data comes from a different profile.
159    std::vector<BookmarkNodeData::Element> elements = data.elements;
160    for (size_t i = 0; i < elements.size(); ++i)
161      node_data->elements.push_back(CreateApiNodeDataElement(elements[i]));
162  }
163  return node_data.Pass();
164}
165
166}  // namespace
167
168BookmarkManagerPrivateEventRouter::BookmarkManagerPrivateEventRouter(
169    content::BrowserContext* browser_context,
170    BookmarkModel* bookmark_model)
171    : browser_context_(browser_context), bookmark_model_(bookmark_model) {
172  bookmark_model_->AddObserver(this);
173}
174
175BookmarkManagerPrivateEventRouter::~BookmarkManagerPrivateEventRouter() {
176  if (bookmark_model_)
177    bookmark_model_->RemoveObserver(this);
178}
179
180void BookmarkManagerPrivateEventRouter::DispatchEvent(
181    const std::string& event_name,
182    scoped_ptr<base::ListValue> event_args) {
183  extensions::EventRouter::Get(browser_context_)->BroadcastEvent(
184      make_scoped_ptr(new extensions::Event(event_name, event_args.Pass())));
185}
186
187void BookmarkManagerPrivateEventRouter::BookmarkModelChanged() {}
188
189void BookmarkManagerPrivateEventRouter::BookmarkModelBeingDeleted(
190    BookmarkModel* model) {
191  bookmark_model_ = NULL;
192}
193
194void BookmarkManagerPrivateEventRouter::OnWillChangeBookmarkMetaInfo(
195    BookmarkModel* model,
196    const BookmarkNode* node) {
197  DCHECK(prev_meta_info_.empty());
198  if (node->GetMetaInfoMap())
199    prev_meta_info_ = *node->GetMetaInfoMap();
200}
201
202void BookmarkManagerPrivateEventRouter::BookmarkMetaInfoChanged(
203    BookmarkModel* model,
204    const BookmarkNode* node) {
205  const BookmarkNode::MetaInfoMap* new_meta_info = node->GetMetaInfoMap();
206  bookmark_manager_private::MetaInfoFields changes;
207
208  // Identify changed/removed fields:
209  for (BookmarkNode::MetaInfoMap::const_iterator it = prev_meta_info_.begin();
210       it != prev_meta_info_.end();
211       ++it) {
212    if (!new_meta_info) {
213      changes.additional_properties[it->first] = "";
214    } else {
215      BookmarkNode::MetaInfoMap::const_iterator new_meta_field =
216          new_meta_info->find(it->first);
217      if (new_meta_field == new_meta_info->end()) {
218        changes.additional_properties[it->first] = "";
219      } else if (it->second != new_meta_field->second) {
220        changes.additional_properties[it->first] = new_meta_field->second;
221      }
222    }
223  }
224
225  // Identify added fields:
226  if (new_meta_info) {
227    for (BookmarkNode::MetaInfoMap::const_iterator it = new_meta_info->begin();
228         it != new_meta_info->end();
229         ++it) {
230      BookmarkNode::MetaInfoMap::const_iterator prev_meta_field =
231          prev_meta_info_.find(it->first);
232      if (prev_meta_field == prev_meta_info_.end())
233        changes.additional_properties[it->first] = it->second;
234    }
235  }
236
237  prev_meta_info_.clear();
238  DispatchEvent(bookmark_manager_private::OnMetaInfoChanged::kEventName,
239                bookmark_manager_private::OnMetaInfoChanged::Create(
240                    base::Int64ToString(node->id()), changes));
241}
242
243BookmarkManagerPrivateAPI::BookmarkManagerPrivateAPI(
244    content::BrowserContext* browser_context)
245    : browser_context_(browser_context) {
246  EventRouter* event_router = EventRouter::Get(browser_context);
247  event_router->RegisterObserver(
248      this, bookmark_manager_private::OnMetaInfoChanged::kEventName);
249}
250
251BookmarkManagerPrivateAPI::~BookmarkManagerPrivateAPI() {}
252
253void BookmarkManagerPrivateAPI::Shutdown() {
254  EventRouter::Get(browser_context_)->UnregisterObserver(this);
255}
256
257static base::LazyInstance<
258    BrowserContextKeyedAPIFactory<BookmarkManagerPrivateAPI> > g_factory =
259    LAZY_INSTANCE_INITIALIZER;
260
261// static
262BrowserContextKeyedAPIFactory<BookmarkManagerPrivateAPI>*
263BookmarkManagerPrivateAPI::GetFactoryInstance() {
264  return g_factory.Pointer();
265}
266
267void BookmarkManagerPrivateAPI::OnListenerAdded(
268    const EventListenerInfo& details) {
269  EventRouter::Get(browser_context_)->UnregisterObserver(this);
270  event_router_.reset(new BookmarkManagerPrivateEventRouter(
271      browser_context_,
272      BookmarkModelFactory::GetForProfile(
273          Profile::FromBrowserContext(browser_context_))));
274}
275
276BookmarkManagerPrivateDragEventRouter::BookmarkManagerPrivateDragEventRouter(
277    Profile* profile,
278    content::WebContents* web_contents)
279    : profile_(profile), web_contents_(web_contents) {
280  BookmarkTabHelper* bookmark_tab_helper =
281      BookmarkTabHelper::FromWebContents(web_contents_);
282  bookmark_tab_helper->set_bookmark_drag_delegate(this);
283}
284
285BookmarkManagerPrivateDragEventRouter::
286    ~BookmarkManagerPrivateDragEventRouter() {
287  BookmarkTabHelper* bookmark_tab_helper =
288      BookmarkTabHelper::FromWebContents(web_contents_);
289  if (bookmark_tab_helper->bookmark_drag_delegate() == this)
290    bookmark_tab_helper->set_bookmark_drag_delegate(NULL);
291}
292
293void BookmarkManagerPrivateDragEventRouter::DispatchEvent(
294    const std::string& event_name,
295    scoped_ptr<base::ListValue> args) {
296  EventRouter* event_router = EventRouter::Get(profile_);
297  if (!event_router)
298    return;
299
300  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
301  event_router->BroadcastEvent(event.Pass());
302}
303
304void BookmarkManagerPrivateDragEventRouter::OnDragEnter(
305    const BookmarkNodeData& data) {
306  if (data.size() == 0)
307    return;
308  DispatchEvent(bookmark_manager_private::OnDragEnter::kEventName,
309                bookmark_manager_private::OnDragEnter::Create(
310                    *CreateApiBookmarkNodeData(profile_, data)));
311}
312
313void BookmarkManagerPrivateDragEventRouter::OnDragOver(
314    const BookmarkNodeData& data) {
315  // Intentionally empty since these events happens too often and floods the
316  // message queue. We do not need this event for the bookmark manager anyway.
317}
318
319void BookmarkManagerPrivateDragEventRouter::OnDragLeave(
320    const BookmarkNodeData& data) {
321  if (data.size() == 0)
322    return;
323  DispatchEvent(bookmark_manager_private::OnDragLeave::kEventName,
324                bookmark_manager_private::OnDragLeave::Create(
325                    *CreateApiBookmarkNodeData(profile_, data)));
326}
327
328void BookmarkManagerPrivateDragEventRouter::OnDrop(
329    const BookmarkNodeData& data) {
330  if (data.size() == 0)
331    return;
332  DispatchEvent(bookmark_manager_private::OnDrop::kEventName,
333                bookmark_manager_private::OnDrop::Create(
334                    *CreateApiBookmarkNodeData(profile_, data)));
335
336  // Make a copy that is owned by this instance.
337  ClearBookmarkNodeData();
338  bookmark_drag_data_ = data;
339}
340
341const BookmarkNodeData*
342BookmarkManagerPrivateDragEventRouter::GetBookmarkNodeData() {
343  if (bookmark_drag_data_.is_valid())
344    return &bookmark_drag_data_;
345  return NULL;
346}
347
348void BookmarkManagerPrivateDragEventRouter::ClearBookmarkNodeData() {
349  bookmark_drag_data_.Clear();
350}
351
352bool ClipboardBookmarkManagerFunction::CopyOrCut(bool cut,
353    const std::vector<std::string>& id_list) {
354  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
355  std::vector<const BookmarkNode*> nodes;
356  EXTENSION_FUNCTION_VALIDATE(GetNodesFromVector(model, id_list, &nodes));
357  bookmark_utils::CopyToClipboard(model, nodes, cut);
358  return true;
359}
360
361bool BookmarkManagerPrivateCopyFunction::RunOnReady() {
362  scoped_ptr<Copy::Params> params(Copy::Params::Create(*args_));
363  EXTENSION_FUNCTION_VALIDATE(params);
364  return CopyOrCut(false, params->id_list);
365}
366
367bool BookmarkManagerPrivateCutFunction::RunOnReady() {
368  if (!EditBookmarksEnabled())
369    return false;
370
371  scoped_ptr<Cut::Params> params(Cut::Params::Create(*args_));
372  EXTENSION_FUNCTION_VALIDATE(params);
373  return CopyOrCut(true, params->id_list);
374}
375
376bool BookmarkManagerPrivatePasteFunction::RunOnReady() {
377  if (!EditBookmarksEnabled())
378    return false;
379
380  scoped_ptr<Paste::Params> params(Paste::Params::Create(*args_));
381  EXTENSION_FUNCTION_VALIDATE(params);
382  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
383  const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
384  if (!parent_node) {
385    error_ = bookmark_keys::kNoParentError;
386    return false;
387  }
388  bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node);
389  if (!can_paste)
390    return false;
391
392  // We want to use the highest index of the selected nodes as a destination.
393  std::vector<const BookmarkNode*> nodes;
394  // No need to test return value, if we got an empty list, we insert at end.
395  if (params->selected_id_list)
396    GetNodesFromVector(model, *params->selected_id_list, &nodes);
397  int highest_index = -1;  // -1 means insert at end of list.
398  for (size_t i = 0; i < nodes.size(); ++i) {
399    // + 1 so that we insert after the selection.
400    int index = parent_node->GetIndexOf(nodes[i]) + 1;
401    if (index > highest_index)
402      highest_index = index;
403  }
404
405  bookmark_utils::PasteFromClipboard(model, parent_node, highest_index);
406  return true;
407}
408
409bool BookmarkManagerPrivateCanPasteFunction::RunOnReady() {
410  if (!EditBookmarksEnabled())
411    return false;
412
413  scoped_ptr<CanPaste::Params> params(CanPaste::Params::Create(*args_));
414  EXTENSION_FUNCTION_VALIDATE(params);
415
416  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
417  const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
418  if (!parent_node) {
419    error_ = bookmark_keys::kNoParentError;
420    return false;
421  }
422  bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node);
423  SetResult(new base::FundamentalValue(can_paste));
424  return true;
425}
426
427bool BookmarkManagerPrivateSortChildrenFunction::RunOnReady() {
428  if (!EditBookmarksEnabled())
429    return false;
430
431  scoped_ptr<SortChildren::Params> params(SortChildren::Params::Create(*args_));
432  EXTENSION_FUNCTION_VALIDATE(params);
433
434  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
435  const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
436  if (!parent_node) {
437    error_ = bookmark_keys::kNoParentError;
438    return false;
439  }
440  model->SortChildren(parent_node);
441  return true;
442}
443
444bool BookmarkManagerPrivateGetStringsFunction::RunAsync() {
445  base::DictionaryValue* localized_strings = new base::DictionaryValue();
446
447  localized_strings->SetString("title",
448      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TITLE));
449  localized_strings->SetString("search_button",
450      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH_BUTTON));
451  localized_strings->SetString("organize_menu",
452      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU));
453  localized_strings->SetString("show_in_folder",
454      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
455  localized_strings->SetString("sort",
456      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SORT));
457  localized_strings->SetString("import_menu",
458      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_IMPORT_MENU));
459  localized_strings->SetString("export_menu",
460      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_EXPORT_MENU));
461  localized_strings->SetString("rename_folder",
462      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_RENAME_FOLDER));
463  localized_strings->SetString("edit",
464      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_EDIT));
465  localized_strings->SetString("should_open_all",
466      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL));
467  localized_strings->SetString("open_incognito",
468      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_INCOGNITO));
469  localized_strings->SetString("open_in_new_tab",
470      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_IN_NEW_TAB));
471  localized_strings->SetString("open_in_new_window",
472      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_IN_NEW_WINDOW));
473  localized_strings->SetString("add_new_bookmark",
474      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
475  localized_strings->SetString("new_folder",
476      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_NEW_FOLDER));
477  localized_strings->SetString("open_all",
478      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL));
479  localized_strings->SetString("open_all_new_window",
480      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
481  localized_strings->SetString("open_all_incognito",
482      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
483  localized_strings->SetString("remove",
484      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_REMOVE));
485  localized_strings->SetString("copy",
486      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_COPY));
487  localized_strings->SetString("cut",
488      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_CUT));
489  localized_strings->SetString("paste",
490      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PASTE));
491  localized_strings->SetString("delete",
492      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_DELETE));
493  localized_strings->SetString("undo_delete",
494      l10n_util::GetStringUTF16(IDS_UNDO_DELETE));
495  localized_strings->SetString("new_folder_name",
496      l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME));
497  localized_strings->SetString("name_input_placeholder",
498      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER));
499  localized_strings->SetString("url_input_placeholder",
500      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER));
501  localized_strings->SetString("invalid_url",
502      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_INVALID_URL));
503  localized_strings->SetString("recent",
504      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_RECENT));
505  localized_strings->SetString("search",
506      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH));
507  localized_strings->SetString("save",
508      l10n_util::GetStringUTF16(IDS_SAVE));
509  localized_strings->SetString("cancel",
510      l10n_util::GetStringUTF16(IDS_CANCEL));
511
512  webui::SetFontAndTextDirection(localized_strings);
513
514  SetResult(localized_strings);
515
516  // This is needed because unlike the rest of these functions, this class
517  // inherits from AsyncFunction directly, rather than BookmarkFunction.
518  SendResponse(true);
519
520  return true;
521}
522
523bool BookmarkManagerPrivateStartDragFunction::RunOnReady() {
524  if (!EditBookmarksEnabled())
525    return false;
526
527  scoped_ptr<StartDrag::Params> params(StartDrag::Params::Create(*args_));
528  EXTENSION_FUNCTION_VALIDATE(params);
529
530  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
531  std::vector<const BookmarkNode*> nodes;
532  EXTENSION_FUNCTION_VALIDATE(
533      GetNodesFromVector(model, params->id_list, &nodes));
534
535  WebContents* web_contents =
536      WebContents::FromRenderViewHost(render_view_host_);
537  if (GetViewType(web_contents) == VIEW_TYPE_TAB_CONTENTS) {
538    WebContents* web_contents =
539        dispatcher()->delegate()->GetAssociatedWebContents();
540    CHECK(web_contents);
541
542    ui::DragDropTypes::DragEventSource source =
543        ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE;
544    if (params->is_from_touch)
545      source = ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH;
546
547    chrome::DragBookmarks(
548        GetProfile(), nodes, web_contents->GetNativeView(), source);
549
550    return true;
551  } else {
552    NOTREACHED();
553    return false;
554  }
555}
556
557bool BookmarkManagerPrivateDropFunction::RunOnReady() {
558  if (!EditBookmarksEnabled())
559    return false;
560
561  scoped_ptr<Drop::Params> params(Drop::Params::Create(*args_));
562  EXTENSION_FUNCTION_VALIDATE(params);
563
564  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
565
566  const BookmarkNode* drop_parent = GetNodeFromString(model, params->parent_id);
567  if (!drop_parent) {
568    error_ = bookmark_keys::kNoParentError;
569    return false;
570  }
571
572  int drop_index;
573  if (params->index)
574    drop_index = *params->index;
575  else
576    drop_index = drop_parent->child_count();
577
578  WebContents* web_contents =
579      WebContents::FromRenderViewHost(render_view_host_);
580  if (GetViewType(web_contents) == VIEW_TYPE_TAB_CONTENTS) {
581    WebContents* web_contents =
582        dispatcher()->delegate()->GetAssociatedWebContents();
583    CHECK(web_contents);
584    ExtensionWebUI* web_ui =
585        static_cast<ExtensionWebUI*>(web_contents->GetWebUI()->GetController());
586    CHECK(web_ui);
587    BookmarkManagerPrivateDragEventRouter* router =
588        web_ui->bookmark_manager_private_drag_event_router();
589
590    DCHECK(router);
591    const BookmarkNodeData* drag_data = router->GetBookmarkNodeData();
592    if (drag_data == NULL) {
593      NOTREACHED() <<"Somehow we're dropping null bookmark data";
594      return false;
595    }
596    chrome::DropBookmarks(GetProfile(), *drag_data, drop_parent, drop_index);
597
598    router->ClearBookmarkNodeData();
599    return true;
600  } else {
601    NOTREACHED();
602    return false;
603  }
604}
605
606bool BookmarkManagerPrivateGetSubtreeFunction::RunOnReady() {
607  scoped_ptr<GetSubtree::Params> params(GetSubtree::Params::Create(*args_));
608  EXTENSION_FUNCTION_VALIDATE(params);
609
610  const BookmarkNode* node = NULL;
611
612  if (params->id == "") {
613    BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
614    node = model->root_node();
615  } else {
616    node = GetBookmarkNodeFromId(params->id);
617    if (!node)
618      return false;
619  }
620
621  std::vector<linked_ptr<api::bookmarks::BookmarkTreeNode> > nodes;
622  if (params->folders_only)
623    bookmark_api_helpers::AddNodeFoldersOnly(node, &nodes, true);
624  else
625    bookmark_api_helpers::AddNode(node, &nodes, true);
626  results_ = GetSubtree::Results::Create(nodes);
627  return true;
628}
629
630bool BookmarkManagerPrivateCanEditFunction::RunOnReady() {
631  PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile());
632  SetResult(new base::FundamentalValue(
633      prefs->GetBoolean(prefs::kEditBookmarksEnabled)));
634  return true;
635}
636
637bool BookmarkManagerPrivateRecordLaunchFunction::RunOnReady() {
638  RecordBookmarkLaunch(NULL, BOOKMARK_LAUNCH_LOCATION_MANAGER);
639  return true;
640}
641
642bool BookmarkManagerPrivateCreateWithMetaInfoFunction::RunOnReady() {
643  scoped_ptr<CreateWithMetaInfo::Params> params(
644      CreateWithMetaInfo::Params::Create(*args_));
645  EXTENSION_FUNCTION_VALIDATE(params);
646
647  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
648  const BookmarkNode* node = CreateBookmarkNode(
649      model, params->bookmark, &params->meta_info.additional_properties);
650  if (!node)
651    return false;
652
653  scoped_ptr<api::bookmarks::BookmarkTreeNode> result_node(
654      bookmark_api_helpers::GetBookmarkTreeNode(node, false, false));
655  results_ = CreateWithMetaInfo::Results::Create(*result_node);
656
657  return true;
658}
659
660bool BookmarkManagerPrivateGetMetaInfoFunction::RunOnReady() {
661  scoped_ptr<GetMetaInfo::Params> params(GetMetaInfo::Params::Create(*args_));
662  EXTENSION_FUNCTION_VALIDATE(params);
663
664  const BookmarkNode* node = GetBookmarkNodeFromId(params->id);
665  if (!node)
666    return false;
667
668  if (params->key) {
669    std::string value;
670    if (node->GetMetaInfo(*params->key, &value)) {
671      GetMetaInfo::Results::Value result;
672      result.as_string.reset(new std::string(value));
673      results_ = GetMetaInfo::Results::Create(result);
674    }
675  } else {
676    GetMetaInfo::Results::Value result;
677    result.as_meta_info_fields.reset(
678        new bookmark_manager_private::MetaInfoFields);
679
680    const BookmarkNode::MetaInfoMap* meta_info = node->GetMetaInfoMap();
681    if (meta_info)
682      result.as_meta_info_fields->additional_properties = *meta_info;
683    results_ = GetMetaInfo::Results::Create(result);
684  }
685
686  return true;
687}
688
689bool BookmarkManagerPrivateSetMetaInfoFunction::RunOnReady() {
690  scoped_ptr<SetMetaInfo::Params> params(SetMetaInfo::Params::Create(*args_));
691  EXTENSION_FUNCTION_VALIDATE(params);
692
693  const BookmarkNode* node = GetBookmarkNodeFromId(params->id);
694  if (!node)
695    return false;
696
697  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
698  model->SetNodeMetaInfo(node, params->key, params->value);
699  return true;
700}
701
702bool BookmarkManagerPrivateUpdateMetaInfoFunction::RunOnReady() {
703  scoped_ptr<UpdateMetaInfo::Params> params(
704      UpdateMetaInfo::Params::Create(*args_));
705  EXTENSION_FUNCTION_VALIDATE(params);
706
707  const BookmarkNode* node = GetBookmarkNodeFromId(params->id);
708  if (!node)
709    return false;
710
711  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
712  BookmarkNode::MetaInfoMap new_meta_info(
713      params->meta_info_changes.additional_properties);
714  if (node->GetMetaInfoMap()) {
715    new_meta_info.insert(node->GetMetaInfoMap()->begin(),
716                         node->GetMetaInfoMap()->end());
717  }
718  model->SetNodeMetaInfoMap(node, new_meta_info);
719
720  return true;
721}
722
723bool BookmarkManagerPrivateCanOpenNewWindowsFunction::RunOnReady() {
724  bool can_open_new_windows = true;
725  SetResult(new base::FundamentalValue(can_open_new_windows));
726  return true;
727}
728
729bool BookmarkManagerPrivateRemoveTreesFunction::RunOnReady() {
730  scoped_ptr<RemoveTrees::Params> params(RemoveTrees::Params::Create(*args_));
731  EXTENSION_FUNCTION_VALIDATE(params);
732
733  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
734#if !defined(OS_ANDROID)
735  bookmarks::ScopedGroupBookmarkActions group_deletes(model);
736#endif
737  int64 id;
738  for (size_t i = 0; i < params->id_list.size(); ++i) {
739    if (!GetBookmarkIdAsInt64(params->id_list[i], &id))
740      return false;
741    if (!bookmark_api_helpers::RemoveNode(model, id, true, &error_))
742      return false;
743  }
744
745  return true;
746}
747
748bool BookmarkManagerPrivateUndoFunction::RunOnReady() {
749#if !defined(OS_ANDROID)
750  BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
751      Undo();
752#endif
753
754  return true;
755}
756
757bool BookmarkManagerPrivateRedoFunction::RunOnReady() {
758#if !defined(OS_ANDROID)
759  BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
760      Redo();
761#endif
762
763  return true;
764}
765
766bool BookmarkManagerPrivateGetUndoInfoFunction::RunOnReady() {
767#if !defined(OS_ANDROID)
768  UndoManager* undo_manager =
769      BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager();
770
771  UndoInfo::Results::Result result;
772  result.enabled = undo_manager->undo_count() > 0;
773  result.label = base::UTF16ToUTF8(undo_manager->GetUndoLabel());
774
775  results_ = UndoInfo::Results::Create(result);
776#endif  // !defined(OS_ANDROID)
777
778  return true;
779}
780
781bool BookmarkManagerPrivateGetRedoInfoFunction::RunOnReady() {
782#if !defined(OS_ANDROID)
783  UndoManager* undo_manager =
784      BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager();
785
786  RedoInfo::Results::Result result;
787  result.enabled = undo_manager->redo_count() > 0;
788  result.label = base::UTF16ToUTF8(undo_manager->GetRedoLabel());
789
790  results_ = RedoInfo::Results::Create(result);
791#endif  // !defined(OS_ANDROID)
792
793  return true;
794}
795
796}  // namespace extensions
797