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