bookmark_manager_private_api.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/memory/linked_ptr.h"
10#include "base/prefs/pref_service.h"
11#include "base/strings/string_number_conversions.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/values.h"
14#include "chrome/browser/bookmarks/bookmark_model.h"
15#include "chrome/browser/bookmarks/bookmark_model_factory.h"
16#include "chrome/browser/bookmarks/bookmark_node_data.h"
17#include "chrome/browser/bookmarks/bookmark_stats.h"
18#include "chrome/browser/bookmarks/bookmark_utils.h"
19#include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_constants.h"
20#include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h"
21#include "chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.h"
22#include "chrome/browser/extensions/extension_function_dispatcher.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/browser/undo/bookmark_undo_utils.h"
29#include "chrome/common/extensions/api/bookmark_manager_private.h"
30#include "chrome/common/pref_names.h"
31#include "components/user_prefs/user_prefs.h"
32#include "content/public/browser/render_view_host.h"
33#include "content/public/browser/web_contents.h"
34#include "content/public/browser/web_contents_view.h"
35#include "content/public/browser/web_ui.h"
36#include "extensions/browser/event_router.h"
37#include "extensions/browser/extension_system.h"
38#include "extensions/browser/view_type_utils.h"
39#include "grit/generated_resources.h"
40#include "ui/base/dragdrop/drag_drop_types.h"
41#include "ui/base/l10n/l10n_util.h"
42#include "ui/base/webui/web_ui_util.h"
43
44#if defined(OS_WIN)
45#include "win8/util/win8_util.h"
46#endif  // OS_WIN
47
48namespace extensions {
49
50namespace bookmark_keys = bookmark_api_constants;
51namespace bookmark_manager_private = api::bookmark_manager_private;
52namespace CanPaste = api::bookmark_manager_private::CanPaste;
53namespace Copy = api::bookmark_manager_private::Copy;
54namespace Cut = api::bookmark_manager_private::Cut;
55namespace Drop = api::bookmark_manager_private::Drop;
56namespace GetSubtree = api::bookmark_manager_private::GetSubtree;
57namespace manager_keys = bookmark_manager_api_constants;
58namespace GetMetaInfo = api::bookmark_manager_private::GetMetaInfo;
59namespace Paste = api::bookmark_manager_private::Paste;
60namespace RedoInfo = api::bookmark_manager_private::GetRedoInfo;
61namespace RemoveTrees = api::bookmark_manager_private::RemoveTrees;
62namespace SetMetaInfo = api::bookmark_manager_private::SetMetaInfo;
63namespace SortChildren = api::bookmark_manager_private::SortChildren;
64namespace StartDrag = api::bookmark_manager_private::StartDrag;
65namespace UndoInfo = api::bookmark_manager_private::GetUndoInfo;
66
67using content::WebContents;
68
69namespace {
70
71// Returns a single bookmark node from the argument ID.
72// This returns NULL in case of failure.
73const BookmarkNode* GetNodeFromString(
74    BookmarkModel* model, const std::string& id_string) {
75  int64 id;
76  if (!base::StringToInt64(id_string, &id))
77    return NULL;
78  return model->GetNodeByID(id);
79}
80
81// Gets a vector of bookmark nodes from the argument list of IDs.
82// This returns false in the case of failure.
83bool GetNodesFromVector(BookmarkModel* model,
84                        const std::vector<std::string>& id_strings,
85                        std::vector<const BookmarkNode*>* nodes) {
86
87  if (id_strings.empty())
88    return false;
89
90  for (size_t i = 0; i < id_strings.size(); ++i) {
91    const BookmarkNode* node = GetNodeFromString(model, id_strings[i]);
92    if (!node)
93      return false;
94    nodes->push_back(node);
95  }
96
97  return true;
98}
99
100// Recursively adds a node to a list. This is by used |BookmarkNodeDataToJSON|
101// when the data comes from the current profile. In this case we have a
102// BookmarkNode since we got the data from the current profile.
103void AddNodeToList(base::ListValue* list, const BookmarkNode& node) {
104  base::DictionaryValue* dict = new base::DictionaryValue();
105
106  // Add id and parentId so we can associate the data with existing nodes on the
107  // client side.
108  std::string id_string = base::Int64ToString(node.id());
109  dict->SetString(bookmark_keys::kIdKey, id_string);
110
111  std::string parent_id_string = base::Int64ToString(node.parent()->id());
112  dict->SetString(bookmark_keys::kParentIdKey, parent_id_string);
113
114  if (node.is_url())
115    dict->SetString(bookmark_keys::kUrlKey, node.url().spec());
116
117  dict->SetString(bookmark_keys::kTitleKey, node.GetTitle());
118
119  base::ListValue* children = new base::ListValue();
120  for (int i = 0; i < node.child_count(); ++i)
121    AddNodeToList(children, *node.GetChild(i));
122  dict->Set(bookmark_keys::kChildrenKey, children);
123
124  list->Append(dict);
125}
126
127// Recursively adds an element to a list. This is used by
128// |BookmarkNodeDataToJSON| when the data comes from a different profile. When
129// the data comes from a different profile we do not have any IDs or parent IDs.
130void AddElementToList(base::ListValue* list,
131                      const BookmarkNodeData::Element& element) {
132  base::DictionaryValue* dict = new base::DictionaryValue();
133
134  if (element.is_url)
135    dict->SetString(bookmark_keys::kUrlKey, element.url.spec());
136
137  dict->SetString(bookmark_keys::kTitleKey, element.title);
138
139  base::ListValue* children = new base::ListValue();
140  for (size_t i = 0; i < element.children.size(); ++i)
141    AddElementToList(children, element.children[i]);
142  dict->Set(bookmark_keys::kChildrenKey, children);
143
144  list->Append(dict);
145}
146
147// Builds the JSON structure based on the BookmarksDragData.
148void BookmarkNodeDataToJSON(Profile* profile, const BookmarkNodeData& data,
149                            base::ListValue* args) {
150  bool same_profile = data.IsFromProfile(profile);
151  base::DictionaryValue* value = new base::DictionaryValue();
152  value->SetBoolean(manager_keys::kSameProfileKey, same_profile);
153
154  base::ListValue* list = new base::ListValue();
155  if (same_profile) {
156    std::vector<const BookmarkNode*> nodes = data.GetNodes(profile);
157    for (size_t i = 0; i < nodes.size(); ++i)
158      AddNodeToList(list, *nodes[i]);
159  } else {
160    // We do not have an node IDs when the data comes from a different profile.
161    std::vector<BookmarkNodeData::Element> elements = data.elements;
162    for (size_t i = 0; i < elements.size(); ++i)
163      AddElementToList(list, elements[i]);
164  }
165  value->Set(manager_keys::kElementsKey, list);
166
167  args->Append(value);
168}
169
170}  // namespace
171
172BookmarkManagerPrivateEventRouter::BookmarkManagerPrivateEventRouter(
173    Profile* profile,
174    content::WebContents* web_contents)
175    : profile_(profile),
176      web_contents_(web_contents) {
177  BookmarkTabHelper* bookmark_tab_helper =
178      BookmarkTabHelper::FromWebContents(web_contents_);
179  bookmark_tab_helper->set_bookmark_drag_delegate(this);
180}
181
182BookmarkManagerPrivateEventRouter::~BookmarkManagerPrivateEventRouter() {
183  BookmarkTabHelper* bookmark_tab_helper =
184      BookmarkTabHelper::FromWebContents(web_contents_);
185  if (bookmark_tab_helper->bookmark_drag_delegate() == this)
186    bookmark_tab_helper->set_bookmark_drag_delegate(NULL);
187}
188
189void BookmarkManagerPrivateEventRouter::DispatchEvent(
190    const std::string& event_name,
191    scoped_ptr<base::ListValue> args) {
192  if (!ExtensionSystem::Get(profile_)->event_router())
193    return;
194
195  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
196  ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
197}
198
199void BookmarkManagerPrivateEventRouter::DispatchDragEvent(
200    const BookmarkNodeData& data,
201    const std::string& event_name) {
202  if (data.size() == 0)
203    return;
204
205  scoped_ptr<base::ListValue> args(new base::ListValue());
206  BookmarkNodeDataToJSON(profile_, data, args.get());
207  DispatchEvent(event_name, args.Pass());
208}
209
210void BookmarkManagerPrivateEventRouter::OnDragEnter(
211    const BookmarkNodeData& data) {
212  DispatchDragEvent(data, bookmark_manager_private::OnDragEnter::kEventName);
213}
214
215void BookmarkManagerPrivateEventRouter::OnDragOver(
216    const BookmarkNodeData& data) {
217  // Intentionally empty since these events happens too often and floods the
218  // message queue. We do not need this event for the bookmark manager anyway.
219}
220
221void BookmarkManagerPrivateEventRouter::OnDragLeave(
222    const BookmarkNodeData& data) {
223  DispatchDragEvent(data, bookmark_manager_private::OnDragLeave::kEventName);
224}
225
226void BookmarkManagerPrivateEventRouter::OnDrop(const BookmarkNodeData& data) {
227  DispatchDragEvent(data, bookmark_manager_private::OnDrop::kEventName);
228
229  // Make a copy that is owned by this instance.
230  ClearBookmarkNodeData();
231  bookmark_drag_data_ = data;
232}
233
234const BookmarkNodeData*
235BookmarkManagerPrivateEventRouter::GetBookmarkNodeData() {
236  if (bookmark_drag_data_.is_valid())
237    return &bookmark_drag_data_;
238  return NULL;
239}
240
241void BookmarkManagerPrivateEventRouter::ClearBookmarkNodeData() {
242  bookmark_drag_data_.Clear();
243}
244
245bool ClipboardBookmarkManagerFunction::CopyOrCut(bool cut,
246    const std::vector<std::string>& id_list) {
247  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
248  std::vector<const BookmarkNode*> nodes;
249  EXTENSION_FUNCTION_VALIDATE(GetNodesFromVector(model, id_list, &nodes));
250  bookmark_utils::CopyToClipboard(model, nodes, cut);
251  return true;
252}
253
254bool BookmarkManagerPrivateCopyFunction::RunImpl() {
255  scoped_ptr<Copy::Params> params(Copy::Params::Create(*args_));
256  EXTENSION_FUNCTION_VALIDATE(params);
257  return CopyOrCut(false, params->id_list);
258}
259
260bool BookmarkManagerPrivateCutFunction::RunImpl() {
261  if (!EditBookmarksEnabled())
262    return false;
263
264  scoped_ptr<Cut::Params> params(Cut::Params::Create(*args_));
265  EXTENSION_FUNCTION_VALIDATE(params);
266  return CopyOrCut(true, params->id_list);
267}
268
269bool BookmarkManagerPrivatePasteFunction::RunImpl() {
270  if (!EditBookmarksEnabled())
271    return false;
272
273  scoped_ptr<Paste::Params> params(Paste::Params::Create(*args_));
274  EXTENSION_FUNCTION_VALIDATE(params);
275  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
276  const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
277  if (!parent_node) {
278    error_ = bookmark_keys::kNoParentError;
279    return false;
280  }
281  bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node);
282  if (!can_paste)
283    return false;
284
285  // We want to use the highest index of the selected nodes as a destination.
286  std::vector<const BookmarkNode*> nodes;
287  // No need to test return value, if we got an empty list, we insert at end.
288  if (params->selected_id_list)
289    GetNodesFromVector(model, *params->selected_id_list, &nodes);
290  int highest_index = -1;  // -1 means insert at end of list.
291  for (size_t i = 0; i < nodes.size(); ++i) {
292    // + 1 so that we insert after the selection.
293    int index = parent_node->GetIndexOf(nodes[i]) + 1;
294    if (index > highest_index)
295      highest_index = index;
296  }
297
298  bookmark_utils::PasteFromClipboard(model, parent_node, highest_index);
299  return true;
300}
301
302bool BookmarkManagerPrivateCanPasteFunction::RunImpl() {
303  if (!EditBookmarksEnabled())
304    return false;
305
306  scoped_ptr<CanPaste::Params> params(CanPaste::Params::Create(*args_));
307  EXTENSION_FUNCTION_VALIDATE(params);
308
309  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
310  const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
311  if (!parent_node) {
312    error_ = bookmark_keys::kNoParentError;
313    return false;
314  }
315  bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node);
316  SetResult(new base::FundamentalValue(can_paste));
317  return true;
318}
319
320bool BookmarkManagerPrivateSortChildrenFunction::RunImpl() {
321  if (!EditBookmarksEnabled())
322    return false;
323
324  scoped_ptr<SortChildren::Params> params(SortChildren::Params::Create(*args_));
325  EXTENSION_FUNCTION_VALIDATE(params);
326
327  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
328  const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
329  if (!parent_node) {
330    error_ = bookmark_keys::kNoParentError;
331    return false;
332  }
333  model->SortChildren(parent_node);
334  return true;
335}
336
337bool BookmarkManagerPrivateGetStringsFunction::RunImpl() {
338  base::DictionaryValue* localized_strings = new base::DictionaryValue();
339
340  localized_strings->SetString("title",
341      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TITLE));
342  localized_strings->SetString("search_button",
343      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH_BUTTON));
344  localized_strings->SetString("organize_menu",
345      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU));
346  localized_strings->SetString("show_in_folder",
347      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
348  localized_strings->SetString("sort",
349      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SORT));
350  localized_strings->SetString("import_menu",
351      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_IMPORT_MENU));
352  localized_strings->SetString("export_menu",
353      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_EXPORT_MENU));
354  localized_strings->SetString("rename_folder",
355      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_RENAME_FOLDER));
356  localized_strings->SetString("edit",
357      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_EDIT));
358  localized_strings->SetString("should_open_all",
359      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL));
360  localized_strings->SetString("open_incognito",
361      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_INCOGNITO));
362  localized_strings->SetString("open_in_new_tab",
363      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_IN_NEW_TAB));
364  localized_strings->SetString("open_in_new_window",
365      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_IN_NEW_WINDOW));
366  localized_strings->SetString("add_new_bookmark",
367      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
368  localized_strings->SetString("new_folder",
369      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_NEW_FOLDER));
370  localized_strings->SetString("open_all",
371      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL));
372  localized_strings->SetString("open_all_new_window",
373      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
374  localized_strings->SetString("open_all_incognito",
375      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
376  localized_strings->SetString("remove",
377      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_REMOVE));
378  localized_strings->SetString("copy",
379      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_COPY));
380  localized_strings->SetString("cut",
381      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_CUT));
382  localized_strings->SetString("paste",
383      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PASTE));
384  localized_strings->SetString("delete",
385      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_DELETE));
386  localized_strings->SetString("undo_delete",
387      l10n_util::GetStringUTF16(IDS_UNDO_DELETE));
388  localized_strings->SetString("new_folder_name",
389      l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME));
390  localized_strings->SetString("name_input_placeholder",
391      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER));
392  localized_strings->SetString("url_input_placeholder",
393      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER));
394  localized_strings->SetString("invalid_url",
395      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_INVALID_URL));
396  localized_strings->SetString("recent",
397      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_RECENT));
398  localized_strings->SetString("search",
399      l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH));
400  localized_strings->SetString("save",
401      l10n_util::GetStringUTF16(IDS_SAVE));
402  localized_strings->SetString("cancel",
403      l10n_util::GetStringUTF16(IDS_CANCEL));
404
405  webui::SetFontAndTextDirection(localized_strings);
406
407  SetResult(localized_strings);
408
409  // This is needed because unlike the rest of these functions, this class
410  // inherits from AsyncFunction directly, rather than BookmarkFunction.
411  SendResponse(true);
412
413  return true;
414}
415
416bool BookmarkManagerPrivateStartDragFunction::RunImpl() {
417  if (!EditBookmarksEnabled())
418    return false;
419
420  scoped_ptr<StartDrag::Params> params(StartDrag::Params::Create(*args_));
421  EXTENSION_FUNCTION_VALIDATE(params);
422
423  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
424  std::vector<const BookmarkNode*> nodes;
425  EXTENSION_FUNCTION_VALIDATE(
426      GetNodesFromVector(model, params->id_list, &nodes));
427
428  WebContents* web_contents =
429      WebContents::FromRenderViewHost(render_view_host_);
430  if (GetViewType(web_contents) == VIEW_TYPE_TAB_CONTENTS) {
431    WebContents* web_contents =
432        dispatcher()->delegate()->GetAssociatedWebContents();
433    CHECK(web_contents);
434
435    ui::DragDropTypes::DragEventSource source =
436        ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE;
437    if (params->is_from_touch)
438      source = ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH;
439
440    chrome::DragBookmarks(
441        GetProfile(), nodes, web_contents->GetView()->GetNativeView(), source);
442
443    return true;
444  } else {
445    NOTREACHED();
446    return false;
447  }
448}
449
450bool BookmarkManagerPrivateDropFunction::RunImpl() {
451  if (!EditBookmarksEnabled())
452    return false;
453
454  scoped_ptr<Drop::Params> params(Drop::Params::Create(*args_));
455  EXTENSION_FUNCTION_VALIDATE(params);
456
457  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
458
459  const BookmarkNode* drop_parent = GetNodeFromString(model, params->parent_id);
460  if (!drop_parent) {
461    error_ = bookmark_keys::kNoParentError;
462    return false;
463  }
464
465  int drop_index;
466  if (params->index)
467    drop_index = *params->index;
468  else
469    drop_index = drop_parent->child_count();
470
471  WebContents* web_contents =
472      WebContents::FromRenderViewHost(render_view_host_);
473  if (GetViewType(web_contents) == VIEW_TYPE_TAB_CONTENTS) {
474    WebContents* web_contents =
475        dispatcher()->delegate()->GetAssociatedWebContents();
476    CHECK(web_contents);
477    ExtensionWebUI* web_ui =
478        static_cast<ExtensionWebUI*>(web_contents->GetWebUI()->GetController());
479    CHECK(web_ui);
480    BookmarkManagerPrivateEventRouter* router =
481        web_ui->bookmark_manager_private_event_router();
482
483    DCHECK(router);
484    const BookmarkNodeData* drag_data = router->GetBookmarkNodeData();
485    if (drag_data == NULL) {
486      NOTREACHED() <<"Somehow we're dropping null bookmark data";
487      return false;
488    }
489    chrome::DropBookmarks(GetProfile(), *drag_data, drop_parent, drop_index);
490
491    router->ClearBookmarkNodeData();
492    return true;
493  } else {
494    NOTREACHED();
495    return false;
496  }
497}
498
499bool BookmarkManagerPrivateGetSubtreeFunction::RunImpl() {
500  scoped_ptr<GetSubtree::Params> params(GetSubtree::Params::Create(*args_));
501  EXTENSION_FUNCTION_VALIDATE(params);
502
503  const BookmarkNode* node = NULL;
504
505  if (params->id == "") {
506    BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
507    node = model->root_node();
508  } else {
509    node = GetBookmarkNodeFromId(params->id);
510    if (!node)
511      return false;
512  }
513
514  std::vector<linked_ptr<api::bookmarks::BookmarkTreeNode> > nodes;
515  if (params->folders_only)
516    bookmark_api_helpers::AddNodeFoldersOnly(node, &nodes, true);
517  else
518    bookmark_api_helpers::AddNode(node, &nodes, true);
519  results_ = GetSubtree::Results::Create(nodes);
520  return true;
521}
522
523bool BookmarkManagerPrivateCanEditFunction::RunImpl() {
524  PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile());
525  SetResult(new base::FundamentalValue(
526      prefs->GetBoolean(prefs::kEditBookmarksEnabled)));
527  return true;
528}
529
530bool BookmarkManagerPrivateRecordLaunchFunction::RunImpl() {
531  RecordBookmarkLaunch(NULL, BOOKMARK_LAUNCH_LOCATION_MANAGER);
532  return true;
533}
534
535bool BookmarkManagerPrivateGetMetaInfoFunction::RunImpl() {
536  scoped_ptr<GetMetaInfo::Params> params(GetMetaInfo::Params::Create(*args_));
537  EXTENSION_FUNCTION_VALIDATE(params);
538
539  const BookmarkNode* node = GetBookmarkNodeFromId(params->id);
540  if (!node)
541    return false;
542
543  std::string value;
544  if (node->GetMetaInfo(params->key, &value))
545    results_ = GetMetaInfo::Results::Create(value);
546  return true;
547}
548
549bool BookmarkManagerPrivateSetMetaInfoFunction::RunImpl() {
550  scoped_ptr<SetMetaInfo::Params> params(SetMetaInfo::Params::Create(*args_));
551  EXTENSION_FUNCTION_VALIDATE(params);
552
553  const BookmarkNode* node = GetBookmarkNodeFromId(params->id);
554  if (!node)
555    return false;
556
557  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
558  model->SetNodeMetaInfo(node, params->key, params->value);
559  return true;
560}
561
562bool BookmarkManagerPrivateCanOpenNewWindowsFunction::RunImpl() {
563  bool can_open_new_windows = true;
564
565#if defined(OS_WIN)
566  if (win8::IsSingleWindowMetroMode())
567    can_open_new_windows = false;
568#endif  // OS_WIN
569
570  SetResult(new base::FundamentalValue(can_open_new_windows));
571  return true;
572}
573
574bool BookmarkManagerPrivateRemoveTreesFunction::RunImpl() {
575  scoped_ptr<RemoveTrees::Params> params(RemoveTrees::Params::Create(*args_));
576  EXTENSION_FUNCTION_VALIDATE(params);
577
578#if !defined(OS_ANDROID)
579  ScopedGroupBookmarkActions group_deletes(GetProfile());
580#endif
581  BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
582  int64 id;
583  for (size_t i = 0; i < params->id_list.size(); ++i) {
584    if (!GetBookmarkIdAsInt64(params->id_list[i], &id))
585      return false;
586    if (!bookmark_api_helpers::RemoveNode(model, id, true, &error_))
587      return false;
588  }
589
590  return true;
591}
592
593bool BookmarkManagerPrivateUndoFunction::RunImpl() {
594#if !defined(OS_ANDROID)
595  BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
596      Undo();
597#endif
598
599  return true;
600}
601
602bool BookmarkManagerPrivateRedoFunction::RunImpl() {
603#if !defined(OS_ANDROID)
604  BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
605      Redo();
606#endif
607
608  return true;
609}
610
611bool BookmarkManagerPrivateGetUndoInfoFunction::RunImpl() {
612#if !defined(OS_ANDROID)
613  UndoManager* undo_manager =
614      BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager();
615
616  UndoInfo::Results::Result result;
617  result.enabled = undo_manager->undo_count() > 0;
618  result.label = base::UTF16ToUTF8(undo_manager->GetUndoLabel());
619
620  results_ = UndoInfo::Results::Create(result);
621#endif  // !defined(OS_ANDROID)
622
623  return true;
624}
625
626bool BookmarkManagerPrivateGetRedoInfoFunction::RunImpl() {
627#if !defined(OS_ANDROID)
628  UndoManager* undo_manager =
629      BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager();
630
631  RedoInfo::Results::Result result;
632  result.enabled = undo_manager->redo_count() > 0;
633  result.label = base::UTF16ToUTF8(undo_manager->GetRedoLabel());
634
635  results_ = RedoInfo::Results::Create(result);
636#endif  // !defined(OS_ANDROID)
637
638  return true;
639}
640
641}  // namespace extensions
642