OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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/extension_bookmark_manager_api.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/json/json_writer.h" | |
10 #include "base/string_number_conversions.h" | |
11 #include "base/values.h" | |
12 #include "chrome/browser/bookmarks/bookmark_model.h" | |
13 #include "chrome/browser/bookmarks/bookmark_node_data.h" | |
14 #include "chrome/browser/bookmarks/bookmark_utils.h" | |
15 #include "chrome/browser/extensions/extension_bookmark_helpers.h" | |
16 #include "chrome/browser/extensions/extension_bookmarks_module_constants.h" | |
17 #include "chrome/browser/extensions/extension_event_router.h" | |
18 #include "chrome/browser/extensions/extension_function_dispatcher.h" | |
19 #include "chrome/browser/extensions/extension_web_ui.h" | |
20 #include "chrome/browser/prefs/pref_service.h" | |
21 #include "chrome/browser/profiles/profile.h" | |
22 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | |
23 #include "chrome/browser/ui/webui/chrome_url_data_manager.h" | |
24 #include "chrome/common/pref_names.h" | |
25 #include "chrome/common/chrome_view_types.h" | |
26 #include "content/browser/renderer_host/render_view_host.h" | |
27 #include "content/browser/tab_contents/tab_contents.h" | |
28 #include "grit/generated_resources.h" | |
29 #include "ui/base/l10n/l10n_util.h" | |
30 | |
31 namespace keys = extension_bookmarks_module_constants; | |
32 | |
33 namespace { | |
34 | |
35 // Returns a single bookmark node from the argument ID. | |
36 // This returns NULL in case of failure. | |
37 const BookmarkNode* GetNodeFromArguments(BookmarkModel* model, | |
38 const ListValue* args) { | |
39 std::string id_string; | |
40 if (!args->GetString(0, &id_string)) | |
41 return NULL; | |
42 int64 id; | |
43 if (!base::StringToInt64(id_string, &id)) | |
44 return NULL; | |
45 return model->GetNodeByID(id); | |
46 } | |
47 | |
48 // Gets a vector of bookmark nodes from the argument list of IDs. | |
49 // This returns false in the case of failure. | |
50 bool GetNodesFromArguments(BookmarkModel* model, const ListValue* args, | |
51 size_t args_index, std::vector<const BookmarkNode*>* nodes) { | |
52 | |
53 ListValue* ids; | |
54 if (!args->GetList(args_index, &ids)) | |
55 return false; | |
56 | |
57 size_t count = ids->GetSize(); | |
58 if (count == 0) | |
59 return false; | |
60 | |
61 for (size_t i = 0; i < count; ++i) { | |
62 std::string id_string; | |
63 if (!ids->GetString(i, &id_string)) | |
64 return false; | |
65 int64 id; | |
66 if (!base::StringToInt64(id_string, &id)) | |
67 return false; | |
68 const BookmarkNode* node = model->GetNodeByID(id); | |
69 if (!node) | |
70 return false; | |
71 nodes->push_back(node); | |
72 } | |
73 | |
74 return true; | |
75 } | |
76 | |
77 // Recursively adds a node to a list. This is by used |BookmarkNodeDataToJSON| | |
78 // when the data comes from the current profile. In this case we have a | |
79 // BookmarkNode since we got the data from the current profile. | |
80 void AddNodeToList(ListValue* list, const BookmarkNode& node) { | |
81 DictionaryValue* dict = new DictionaryValue(); | |
82 | |
83 // Add id and parentId so we can associate the data with existing nodes on the | |
84 // client side. | |
85 std::string id_string = base::Int64ToString(node.id()); | |
86 dict->SetString(keys::kIdKey, id_string); | |
87 | |
88 std::string parent_id_string = base::Int64ToString(node.parent()->id()); | |
89 dict->SetString(keys::kParentIdKey, parent_id_string); | |
90 | |
91 if (node.is_url()) | |
92 dict->SetString(keys::kUrlKey, node.url().spec()); | |
93 | |
94 dict->SetString(keys::kTitleKey, node.GetTitle()); | |
95 | |
96 ListValue* children = new ListValue(); | |
97 for (int i = 0; i < node.child_count(); ++i) | |
98 AddNodeToList(children, *node.GetChild(i)); | |
99 dict->Set(keys::kChildrenKey, children); | |
100 | |
101 list->Append(dict); | |
102 } | |
103 | |
104 // Recursively adds an element to a list. This is used by | |
105 // |BookmarkNodeDataToJSON| when the data comes from a different profile. When | |
106 // the data comes from a different profile we do not have any IDs or parent IDs. | |
107 void AddElementToList(ListValue* list, | |
108 const BookmarkNodeData::Element& element) { | |
109 DictionaryValue* dict = new DictionaryValue(); | |
110 | |
111 if (element.is_url) | |
112 dict->SetString(keys::kUrlKey, element.url.spec()); | |
113 | |
114 dict->SetString(keys::kTitleKey, element.title); | |
115 | |
116 ListValue* children = new ListValue(); | |
117 for (size_t i = 0; i < element.children.size(); ++i) | |
118 AddElementToList(children, element.children[i]); | |
119 dict->Set(keys::kChildrenKey, children); | |
120 | |
121 list->Append(dict); | |
122 } | |
123 | |
124 // Builds the JSON structure based on the BookmarksDragData. | |
125 void BookmarkNodeDataToJSON(Profile* profile, const BookmarkNodeData& data, | |
126 ListValue* args) { | |
127 bool same_profile = data.IsFromProfile(profile); | |
128 DictionaryValue* value = new DictionaryValue(); | |
129 value->SetBoolean(keys::kSameProfileKey, same_profile); | |
130 | |
131 ListValue* list = new ListValue(); | |
132 if (same_profile) { | |
133 std::vector<const BookmarkNode*> nodes = data.GetNodes(profile); | |
134 for (size_t i = 0; i < nodes.size(); ++i) | |
135 AddNodeToList(list, *nodes[i]); | |
136 } else { | |
137 // We do not have an node IDs when the data comes from a different profile. | |
138 std::vector<BookmarkNodeData::Element> elements = data.elements; | |
139 for (size_t i = 0; i < elements.size(); ++i) | |
140 AddElementToList(list, elements[i]); | |
141 } | |
142 value->Set(keys::kElementsKey, list); | |
143 | |
144 args->Append(value); | |
145 } | |
146 | |
147 } // namespace | |
148 | |
149 ExtensionBookmarkManagerEventRouter::ExtensionBookmarkManagerEventRouter( | |
150 Profile* profile, TabContentsWrapper* tab) | |
151 : profile_(profile), | |
152 tab_(tab) { | |
153 tab_->bookmark_tab_helper()->SetBookmarkDragDelegate(this); | |
154 } | |
155 | |
156 ExtensionBookmarkManagerEventRouter::~ExtensionBookmarkManagerEventRouter() { | |
157 if (tab_->bookmark_tab_helper()->GetBookmarkDragDelegate() == this) | |
158 tab_->bookmark_tab_helper()->SetBookmarkDragDelegate(NULL); | |
159 } | |
160 | |
161 void ExtensionBookmarkManagerEventRouter::DispatchEvent(const char* event_name, | |
162 const ListValue* args) { | |
163 if (!profile_->GetExtensionEventRouter()) | |
164 return; | |
165 | |
166 std::string json_args; | |
167 base::JSONWriter::Write(args, false, &json_args); | |
168 profile_->GetExtensionEventRouter()->DispatchEventToRenderers( | |
169 event_name, json_args, NULL, GURL()); | |
170 } | |
171 | |
172 void ExtensionBookmarkManagerEventRouter::DispatchDragEvent( | |
173 const BookmarkNodeData& data, const char* event_name) { | |
174 if (data.size() == 0) | |
175 return; | |
176 | |
177 ListValue args; | |
178 BookmarkNodeDataToJSON(profile_, data, &args); | |
179 DispatchEvent(event_name, &args); | |
180 } | |
181 | |
182 void ExtensionBookmarkManagerEventRouter::OnDragEnter( | |
183 const BookmarkNodeData& data) { | |
184 DispatchDragEvent(data, keys::kOnBookmarkDragEnter); | |
185 } | |
186 | |
187 void ExtensionBookmarkManagerEventRouter::OnDragOver( | |
188 const BookmarkNodeData& data) { | |
189 // Intentionally empty since these events happens too often and floods the | |
190 // message queue. We do not need this event for the bookmark manager anyway. | |
191 } | |
192 | |
193 void ExtensionBookmarkManagerEventRouter::OnDragLeave( | |
194 const BookmarkNodeData& data) { | |
195 DispatchDragEvent(data, keys::kOnBookmarkDragLeave); | |
196 } | |
197 | |
198 void ExtensionBookmarkManagerEventRouter::OnDrop( | |
199 const BookmarkNodeData& data) { | |
200 DispatchDragEvent(data, keys::kOnBookmarkDrop); | |
201 | |
202 // Make a copy that is owned by this instance. | |
203 ClearBookmarkNodeData(); | |
204 bookmark_drag_data_ = data; | |
205 } | |
206 | |
207 const BookmarkNodeData* | |
208 ExtensionBookmarkManagerEventRouter::GetBookmarkNodeData() { | |
209 if (bookmark_drag_data_.is_valid()) | |
210 return &bookmark_drag_data_; | |
211 return NULL; | |
212 } | |
213 | |
214 void ExtensionBookmarkManagerEventRouter::ClearBookmarkNodeData() { | |
215 bookmark_drag_data_.Clear(); | |
216 } | |
217 | |
218 bool ClipboardBookmarkManagerFunction::CopyOrCut(bool cut) { | |
219 BookmarkModel* model = profile()->GetBookmarkModel(); | |
220 std::vector<const BookmarkNode*> nodes; | |
221 EXTENSION_FUNCTION_VALIDATE(GetNodesFromArguments(model, args_.get(), | |
222 0, &nodes)); | |
223 bookmark_utils::CopyToClipboard(model, nodes, cut); | |
224 return true; | |
225 } | |
226 | |
227 bool CopyBookmarkManagerFunction::RunImpl() { | |
228 return CopyOrCut(false); | |
229 } | |
230 | |
231 bool CutBookmarkManagerFunction::RunImpl() { | |
232 if (!EditBookmarksEnabled()) | |
233 return false; | |
234 return CopyOrCut(true); | |
235 } | |
236 | |
237 bool PasteBookmarkManagerFunction::RunImpl() { | |
238 if (!EditBookmarksEnabled()) | |
239 return false; | |
240 BookmarkModel* model = profile()->GetBookmarkModel(); | |
241 const BookmarkNode* parent_node = GetNodeFromArguments(model, args_.get()); | |
242 if (!parent_node) { | |
243 error_ = keys::kNoParentError; | |
244 return false; | |
245 } | |
246 bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node); | |
247 if (!can_paste) | |
248 return false; | |
249 | |
250 // We want to use the highest index of the selected nodes as a destination. | |
251 std::vector<const BookmarkNode*> nodes; | |
252 // No need to test return value, if we got an empty list, we insert at end. | |
253 GetNodesFromArguments(model, args_.get(), 1, &nodes); | |
254 int highest_index = -1; // -1 means insert at end of list. | |
255 for (size_t node = 0; node < nodes.size(); ++node) { | |
256 // + 1 so that we insert after the selection. | |
257 int this_node_index = parent_node->GetIndexOf(nodes[node]) + 1; | |
258 if (this_node_index > highest_index) | |
259 highest_index = this_node_index; | |
260 } | |
261 | |
262 bookmark_utils::PasteFromClipboard(model, parent_node, highest_index); | |
263 return true; | |
264 } | |
265 | |
266 bool CanPasteBookmarkManagerFunction::RunImpl() { | |
267 if (!EditBookmarksEnabled()) | |
268 return false; | |
269 BookmarkModel* model = profile()->GetBookmarkModel(); | |
270 const BookmarkNode* parent_node = GetNodeFromArguments(model, args_.get()); | |
271 if (!parent_node) { | |
272 error_ = keys::kNoParentError; | |
273 return false; | |
274 } | |
275 bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node); | |
276 result_.reset(Value::CreateBooleanValue(can_paste)); | |
277 SendResponse(true); | |
278 return true; | |
279 } | |
280 | |
281 bool SortChildrenBookmarkManagerFunction::RunImpl() { | |
282 if (!EditBookmarksEnabled()) | |
283 return false; | |
284 BookmarkModel* model = profile()->GetBookmarkModel(); | |
285 const BookmarkNode* parent_node = GetNodeFromArguments(model, args_.get()); | |
286 if (!parent_node) { | |
287 error_ = keys::kNoParentError; | |
288 return false; | |
289 } | |
290 model->SortChildren(parent_node); | |
291 return true; | |
292 } | |
293 | |
294 bool BookmarkManagerGetStringsFunction::RunImpl() { | |
295 DictionaryValue* localized_strings = new DictionaryValue(); | |
296 | |
297 localized_strings->SetString("title", | |
298 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TITLE)); | |
299 localized_strings->SetString("search_button", | |
300 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH_BUTTON)); | |
301 localized_strings->SetString("show_in_folder", | |
302 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER)); | |
303 localized_strings->SetString("sort", | |
304 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SORT)); | |
305 localized_strings->SetString("organize_menu", | |
306 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU)); | |
307 localized_strings->SetString("tools_menu", | |
308 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TOOLS_MENU)); | |
309 localized_strings->SetString("import_menu", | |
310 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_IMPORT_MENU)); | |
311 localized_strings->SetString("export_menu", | |
312 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_EXPORT_MENU)); | |
313 localized_strings->SetString("rename_folder", | |
314 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_RENAME_FOLDER)); | |
315 localized_strings->SetString("edit", | |
316 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_EDIT)); | |
317 localized_strings->SetString("should_open_all", | |
318 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL)); | |
319 localized_strings->SetString("open_incognito", | |
320 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_INCOGNITO)); | |
321 localized_strings->SetString("open_in_new_tab", | |
322 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_IN_NEW_TAB)); | |
323 localized_strings->SetString("open_in_new_window", | |
324 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_IN_NEW_WINDOW)); | |
325 localized_strings->SetString("add_new_bookmark", | |
326 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_ADD_NEW_BOOKMARK)); | |
327 localized_strings->SetString("new_folder", | |
328 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_NEW_FOLDER)); | |
329 localized_strings->SetString("open_all", | |
330 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL)); | |
331 localized_strings->SetString("open_all_new_window", | |
332 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW)); | |
333 localized_strings->SetString("open_all_incognito", | |
334 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL_INCOGNITO)); | |
335 localized_strings->SetString("remove", | |
336 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_REMOVE)); | |
337 localized_strings->SetString("copy", | |
338 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_COPY)); | |
339 localized_strings->SetString("cut", | |
340 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_CUT)); | |
341 localized_strings->SetString("paste", | |
342 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PASTE)); | |
343 localized_strings->SetString("delete", | |
344 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_DELETE)); | |
345 localized_strings->SetString("new_folder_name", | |
346 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME)); | |
347 localized_strings->SetString("name_input_placeholder", | |
348 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER)); | |
349 localized_strings->SetString("url_input_placeholder", | |
350 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER)); | |
351 localized_strings->SetString("invalid_url", | |
352 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_INVALID_URL)); | |
353 localized_strings->SetString("recent", | |
354 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_RECENT)); | |
355 localized_strings->SetString("search", | |
356 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH)); | |
357 | |
358 ChromeURLDataManager::DataSource::SetFontAndTextDirection(localized_strings); | |
359 | |
360 result_.reset(localized_strings); | |
361 SendResponse(true); | |
362 return true; | |
363 } | |
364 | |
365 bool StartDragBookmarkManagerFunction::RunImpl() { | |
366 if (!EditBookmarksEnabled()) | |
367 return false; | |
368 BookmarkModel* model = profile()->GetBookmarkModel(); | |
369 std::vector<const BookmarkNode*> nodes; | |
370 EXTENSION_FUNCTION_VALIDATE( | |
371 GetNodesFromArguments(model, args_.get(), 0, &nodes)); | |
372 | |
373 if (render_view_host_->delegate()->GetRenderViewType() == | |
374 content::VIEW_TYPE_TAB_CONTENTS) { | |
375 TabContents* tab_contents = | |
376 dispatcher()->delegate()->GetAssociatedTabContents(); | |
377 CHECK(tab_contents); | |
378 bookmark_utils::DragBookmarks(profile(), nodes, | |
379 tab_contents->GetNativeView()); | |
380 | |
381 return true; | |
382 } else { | |
383 NOTREACHED(); | |
384 return false; | |
385 } | |
386 } | |
387 | |
388 bool DropBookmarkManagerFunction::RunImpl() { | |
389 if (!EditBookmarksEnabled()) | |
390 return false; | |
391 | |
392 BookmarkModel* model = profile()->GetBookmarkModel(); | |
393 | |
394 int64 id; | |
395 std::string id_string; | |
396 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id_string)); | |
397 | |
398 if (!base::StringToInt64(id_string, &id)) { | |
399 error_ = keys::kInvalidIdError; | |
400 return false; | |
401 } | |
402 | |
403 const BookmarkNode* drop_parent = model->GetNodeByID(id); | |
404 if (!drop_parent) { | |
405 error_ = keys::kNoParentError; | |
406 return false; | |
407 } | |
408 | |
409 int drop_index; | |
410 if (args_->GetSize() == 2) | |
411 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(1, &drop_index)); | |
412 else | |
413 drop_index = drop_parent->child_count(); | |
414 | |
415 if (render_view_host_->delegate()->GetRenderViewType() == | |
416 content::VIEW_TYPE_TAB_CONTENTS) { | |
417 TabContents* tab_contents = | |
418 dispatcher()->delegate()->GetAssociatedTabContents(); | |
419 CHECK(tab_contents); | |
420 ExtensionWebUI* web_ui = | |
421 static_cast<ExtensionWebUI*>(tab_contents->web_ui()); | |
422 CHECK(web_ui); | |
423 ExtensionBookmarkManagerEventRouter* router = | |
424 web_ui->extension_bookmark_manager_event_router(); | |
425 | |
426 DCHECK(router); | |
427 const BookmarkNodeData* drag_data = router->GetBookmarkNodeData(); | |
428 if (drag_data == NULL) { | |
429 NOTREACHED() <<"Somehow we're dropping null bookmark data"; | |
430 return false; | |
431 } | |
432 bookmark_utils::PerformBookmarkDrop(profile(), | |
433 *drag_data, | |
434 drop_parent, drop_index); | |
435 | |
436 router->ClearBookmarkNodeData(); | |
437 SendResponse(true); | |
438 return true; | |
439 } else { | |
440 NOTREACHED(); | |
441 return false; | |
442 } | |
443 } | |
444 | |
445 bool GetSubtreeBookmarkManagerFunction::RunImpl() { | |
446 BookmarkModel* model = profile()->GetBookmarkModel(); | |
447 const BookmarkNode* node; | |
448 int64 id; | |
449 std::string id_string; | |
450 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id_string)); | |
451 bool folders_only; | |
452 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &folders_only)); | |
453 if (id_string == "") { | |
454 node = model->root_node(); | |
455 } else { | |
456 if (!base::StringToInt64(id_string, &id)) { | |
457 error_ = keys::kInvalidIdError; | |
458 return false; | |
459 } | |
460 node = model->GetNodeByID(id); | |
461 } | |
462 if (!node) { | |
463 error_ = keys::kNoNodeError; | |
464 return false; | |
465 } | |
466 scoped_ptr<ListValue> json(new ListValue()); | |
467 if (folders_only) { | |
468 extension_bookmark_helpers::AddNodeFoldersOnly(node, | |
469 json.get(), | |
470 true); | |
471 } else { | |
472 extension_bookmark_helpers::AddNode(node, json.get(), true); | |
473 } | |
474 result_.reset(json.release()); | |
475 return true; | |
476 } | |
477 | |
478 bool CanEditBookmarkManagerFunction::RunImpl() { | |
479 result_.reset(Value::CreateBooleanValue( | |
480 profile_->GetPrefs()->GetBoolean(prefs::kEditBookmarksEnabled))); | |
481 return true; | |
482 } | |
483 | |
484 bool RecordLaunchBookmarkFunction::RunImpl() { | |
485 bookmark_utils::RecordBookmarkLaunch(bookmark_utils::LAUNCH_MANAGER); | |
486 return true; | |
487 } | |
OLD | NEW |