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