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