summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarv@chromium.org <arv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-20 02:06:16 +0000
committerarv@chromium.org <arv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-20 02:06:16 +0000
commitced90ae1159e8967837cd13b9155956467a811f9 (patch)
treeb052ff281b583fdcc12f6bea883f83db663ae92f
parentddf796cffe2f905a36764bc2e46cc8325a560c51 (diff)
downloadchromium_src-ced90ae1159e8967837cd13b9155956467a811f9.zip
chromium_src-ced90ae1159e8967837cd13b9155956467a811f9.tar.gz
chromium_src-ced90ae1159e8967837cd13b9155956467a811f9.tar.bz2
Bookmark Manager Drag and Drop backend.
This adds the following methods to chrome.experimental.bookmarkManager: startDrag(idList) drop(parentId, opt_index) as well as the following events: onDragEnter(function(BookmarkDragData)) onDragLeave(function(BookmarkDragData)) onDrop(function(BookmarkDragData)) BUG=32194 TEST=None Review URL: http://codereview.chromium.org/596105 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39540 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/bookmarks/bookmark_drag_data.cc5
-rw-r--r--chrome/browser/bookmarks/bookmark_drag_data.h3
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.cc48
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.h5
-rw-r--r--chrome/browser/extensions/extension_bookmark_manager_api.cc233
-rw-r--r--chrome/browser/extensions/extension_bookmark_manager_api.h69
-rw-r--r--chrome/browser/extensions/extension_bookmarks_module_constants.cc10
-rw-r--r--chrome/browser/extensions/extension_bookmarks_module_constants.h7
-rw-r--r--chrome/browser/extensions/extension_dom_ui.cc12
-rw-r--r--chrome/browser/extensions/extension_dom_ui.h15
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc2
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.cc5
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h25
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc9
-rw-r--r--chrome/browser/tab_contents/tab_contents.h13
-rw-r--r--chrome/browser/tab_contents/web_drop_target_win.cc22
-rwxr-xr-xchrome/common/extensions/api/extension_api.json102
17 files changed, 565 insertions, 20 deletions
diff --git a/chrome/browser/bookmarks/bookmark_drag_data.cc b/chrome/browser/bookmarks/bookmark_drag_data.cc
index 1b4b7de..5a5340b 100644
--- a/chrome/browser/bookmarks/bookmark_drag_data.cc
+++ b/chrome/browser/bookmarks/bookmark_drag_data.cc
@@ -261,6 +261,11 @@ const BookmarkNode* BookmarkDragData::GetFirstNode(Profile* profile) const {
return nodes.size() == 1 ? nodes[0] : NULL;
}
+void BookmarkDragData::Clear() {
+ profile_path_.clear();
+ elements.clear();
+}
+
bool BookmarkDragData::IsFromProfile(Profile* profile) const {
// An empty path means the data is not associated with any profile.
return (!profile_path_.empty() &&
diff --git a/chrome/browser/bookmarks/bookmark_drag_data.h b/chrome/browser/bookmarks/bookmark_drag_data.h
index 486d144..9d033ae 100644
--- a/chrome/browser/bookmarks/bookmark_drag_data.h
+++ b/chrome/browser/bookmarks/bookmark_drag_data.h
@@ -124,6 +124,9 @@ struct BookmarkDragData {
// Number of elements.
size_t size() const { return elements.size(); }
+ // Clears the data.
+ void Clear();
+
// Returns true if this data is from the specified profile.
bool IsFromProfile(Profile* profile) const;
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
index fe4ae6e..4aa14eb 100644
--- a/chrome/browser/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -32,6 +32,13 @@
#include "net/base/net_util.h"
#include "views/event.h"
+#if defined(TOOLKIT_VIEWS)
+#include "app/os_exchange_data.h"
+#include "views/drag_utils.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+#endif
+
using base::Time;
namespace {
@@ -245,11 +252,14 @@ int PerformBookmarkDrop(Profile* profile,
const BookmarkDragData& data,
const BookmarkNode* parent_node,
int index) {
- const BookmarkNode* dragged_node = data.GetFirstNode(profile);
+ const std::vector<const BookmarkNode*> dragged_nodes = data.GetNodes(profile);
BookmarkModel* model = profile->GetBookmarkModel();
- if (dragged_node) {
- // Drag from same profile, do a move.
- model->Move(dragged_node, parent_node, index);
+ if (!dragged_nodes.empty()) {
+ // Drag from same profile. Move nodes.
+ for (size_t i = 0; i < dragged_nodes.size(); ++i) {
+ model->Move(dragged_nodes[i], parent_node, index);
+ index = parent_node->IndexOfChild(dragged_nodes[i]) + 1;
+ }
return DragDropTypes::DRAG_MOVE;
} else if (data.has_single_url()) {
// New URL, add it at the specified location.
@@ -314,6 +324,36 @@ void CloneDragData(BookmarkModel* model,
CloneDragDataImpl(model, elements[i], parent, index_to_add_at + i);
}
+
+// Bookmark dragging
+void DragBookmarks(Profile* profile,
+ const std::vector<const BookmarkNode*>& nodes,
+ gfx::NativeView view) {
+ DCHECK(!nodes.empty());
+
+#if defined(TOOLKIT_VIEWS)
+ // Set up our OLE machinery
+ OSExchangeData data;
+ BookmarkDragData drag_data(nodes);
+ drag_data.Write(profile, &data);
+
+ views::RootView* root_view = views::Widget::GetWidgetFromNativeView(view)->GetRootView();
+
+ // Allow nested message loop so we get DnD events as we drag this around.
+ bool was_nested = MessageLoop::current()->IsNested();
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+
+ root_view->StartDragForViewFromMouseEvent(NULL, data,
+ DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE |
+ DragDropTypes::DRAG_LINK);
+
+ MessageLoop::current()->SetNestableTasksAllowed(was_nested);
+#else
+ // TODO(arv): Implement for GTK and Cocoa.
+ NOTIMPLEMENTED();
+#endif
+}
+
void OpenAll(gfx::NativeWindow parent,
Profile* profile,
PageNavigator* navigator,
diff --git a/chrome/browser/bookmarks/bookmark_utils.h b/chrome/browser/bookmarks/bookmark_utils.h
index 0bea122..b63c848 100644
--- a/chrome/browser/bookmarks/bookmark_utils.h
+++ b/chrome/browser/bookmarks/bookmark_utils.h
@@ -71,6 +71,11 @@ void CloneDragData(BookmarkModel* model,
const BookmarkNode* parent,
int index_to_add_at);
+// Begins dragging a group of bookmarks.
+void DragBookmarks(Profile* profile,
+ const std::vector<const BookmarkNode*>& nodes,
+ gfx::NativeView view);
+
// Recursively opens all bookmarks. |initial_disposition| dictates how the
// first URL is opened, all subsequent URLs are opened as background tabs.
// |navigator| is used to open the URLs. If |navigator| is NULL the last
diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.cc b/chrome/browser/extensions/extension_bookmark_manager_api.cc
index d7f63cc..24a01aa 100644
--- a/chrome/browser/extensions/extension_bookmark_manager_api.cc
+++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc
@@ -4,22 +4,30 @@
#include "chrome/browser/extensions/extension_bookmark_manager_api.h"
+#include <vector>
+
#include "app/l10n_util.h"
+#include "base/json/json_writer.h"
+#include "base/string_util.h"
#include "base/values.h"
+#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_html_writer.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/extensions/extension_bookmarks_module_constants.h"
+#include "chrome/browser/extensions/extension_dom_ui.h"
+#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
#include "grit/generated_resources.h"
-#include <vector>
-
namespace keys = extension_bookmarks_module_constants;
namespace {
+typedef RenderViewHostDelegate::BookmarkDrag::DragData DragData;
+
// Returns a single bookmark node from the argument ID.
// This returns NULL in case of failure.
const BookmarkNode* GetNodeFromArguments(BookmarkModel* model,
@@ -57,6 +65,154 @@ bool GetNodesFromArguments(BookmarkModel* model, const ListValue* ids,
return true;
}
+// Recursively adds a node to a list. This is by used |BookmarkDragDataToJSON|
+// when the data comes from the current profile. In this case we have a
+// BookmarkNode since we got the data from the current profile.
+void AddNodeToList(ListValue* list, const BookmarkNode& node) {
+ DictionaryValue* dict = new DictionaryValue();
+
+ // Add id and parentId so we can associate the data with existing nodes on the
+ // client side.
+ std::string id_string = Int64ToString(node.id());
+ dict->SetString(keys::kIdKey, id_string);
+
+ std::string parent_id_string = Int64ToString(node.GetParent()->id());
+ dict->SetString(keys::kParentIdKey, parent_id_string);
+
+ if (node.is_url())
+ dict->SetString(keys::kUrlKey, node.GetURL().spec());
+
+ dict->SetString(keys::kTitleKey, node.GetTitle());
+
+ ListValue* children = new ListValue();
+ for (int i = 0; i < node.GetChildCount(); ++i)
+ AddNodeToList(children, *node.GetChild(i));
+ dict->Set(keys::kChildrenKey, children);
+
+ list->Append(dict);
+}
+
+// Recursively adds an element to a list. This is by used
+// |BookmarkDragDataToJSON| when the data comes from a different profile. When
+// the data comes from a different profile we do not have any IDs or parent IDs.
+void AddElementToList(ListValue* list,
+ const BookmarkDragData::Element& element) {
+ DictionaryValue* dict = new DictionaryValue();
+
+ if (element.is_url)
+ dict->SetString(keys::kUrlKey, element.url.spec());
+
+ dict->SetString(keys::kTitleKey, UTF16ToWide(element.title));
+
+ ListValue* children = new ListValue();
+ for (size_t i = 0; i < element.children.size(); ++i)
+ AddElementToList(children, element.children[i]);
+ dict->Set(keys::kChildrenKey, children);
+
+ list->Append(dict);
+}
+
+// Builds the JSON structure based on the BookmarksDragData.
+void BookmarkDragDataToJSON(Profile* profile, const BookmarkDragData& data,
+ ListValue* args) {
+ bool same_profile = data.IsFromProfile(profile);
+ DictionaryValue* value = new DictionaryValue();
+ value->SetBoolean(keys::kSameProfileKey, same_profile);
+
+ ListValue* list = new ListValue();
+ if (same_profile) {
+ std::vector<const BookmarkNode*> nodes = data.GetNodes(profile);
+ for (size_t i = 0; i < nodes.size(); ++i)
+ AddNodeToList(list, *nodes[i]);
+ } else {
+ // We do not have an node IDs when the data comes from a different profile.
+ std::vector<BookmarkDragData::Element> elements = data.elements;
+ for (size_t i = 0; i < elements.size(); ++i)
+ AddElementToList(list, elements[i]);
+ }
+ value->Set(keys::kElementsKey, list);
+
+ args->Append(value);
+}
+
+// This is the platform specific function that takes the drag data and creates
+// the BookmarkDragData as needed.
+bool GetBookmarkDragData(const DragData* data,
+ BookmarkDragData* bookmark_drag_data) {
+#if defined(TOOLKIT_VIEWS)
+ // On TOOLKIT_VIEWS DragData is OSExchangeData.
+ return bookmark_drag_data->Read(*data);
+#else
+ NOTIMPLEMENTED();
+ return false;
+#endif
+}
+
+} // namespace
+
+ExtensionBookmarkManagerEventRouter::ExtensionBookmarkManagerEventRouter(
+ Profile* profile, TabContents* tab_contents)
+ : profile_(profile),
+ tab_contents_(tab_contents) {
+ tab_contents_->SetBookmarkDragDelegate(this);
+}
+
+ExtensionBookmarkManagerEventRouter::~ExtensionBookmarkManagerEventRouter() {
+ if (tab_contents_->GetBookmarkDragDelegate() == this)
+ tab_contents_->SetBookmarkDragDelegate(NULL);
+}
+
+void ExtensionBookmarkManagerEventRouter::DispatchEvent(const char* event_name,
+ const ListValue* args) {
+ if (!profile_->GetExtensionMessageService())
+ return;
+
+ std::string json_args;
+ base::JSONWriter::Write(args, false, &json_args);
+ profile_->GetExtensionMessageService()->
+ DispatchEventToRenderers(event_name, json_args);
+}
+
+void ExtensionBookmarkManagerEventRouter::DispatchDragEvent(
+ const DragData* data, const char* event_name) {
+ BookmarkDragData bookmark_drag_data;
+ if (::GetBookmarkDragData(data, &bookmark_drag_data)) {
+ ListValue args;
+ BookmarkDragDataToJSON(profile_, bookmark_drag_data, &args);
+ DispatchEvent(event_name, &args);
+ }
+}
+
+void ExtensionBookmarkManagerEventRouter::OnDragEnter(const DragData* data) {
+ DispatchDragEvent(data, keys::kOnBookmarkDragEnter);
+}
+
+void ExtensionBookmarkManagerEventRouter::OnDragOver(const DragData* data) {
+ // Intentionally empty since these events happens too often and floods the
+ // message queue. We do not need this event for the bookmark manager anyway.
+}
+
+void ExtensionBookmarkManagerEventRouter::OnDragLeave(const DragData* data) {
+ DispatchDragEvent(data, keys::kOnBookmarkDragLeave);
+}
+
+void ExtensionBookmarkManagerEventRouter::OnDrop(const DragData* data) {
+ DispatchDragEvent(data, keys::kOnBookmarkDrop);
+
+ // Make a copy that is owned by this instance.
+ ClearBookmarkDragData();
+ ::GetBookmarkDragData(data, &bookmark_drag_data_);
+}
+
+const BookmarkDragData*
+ExtensionBookmarkManagerEventRouter::GetBookmarkDragData() {
+ if (bookmark_drag_data_.is_valid())
+ return &bookmark_drag_data_;
+ return NULL;
+}
+
+void ExtensionBookmarkManagerEventRouter::ClearBookmarkDragData() {
+ bookmark_drag_data_.Clear();
}
bool ClipboardBookmarkManagerFunction::CopyOrCut(bool cut) {
@@ -79,9 +235,13 @@ bool CutBookmarkManagerFunction::RunImpl() {
bool PasteBookmarkManagerFunction::RunImpl() {
BookmarkModel* model = profile()->GetBookmarkModel();
const BookmarkNode* parent_node = GetNodeFromArguments(model, args_.get());
- EXTENSION_FUNCTION_VALIDATE(parent_node);
+ if (!parent_node) {
+ error_ = keys::kNoParentError;
+ return false;
+ }
bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node);
- EXTENSION_FUNCTION_VALIDATE(can_paste);
+ if (!can_paste)
+ return false;
bookmark_utils::PasteFromClipboard(model, parent_node, -1);
return true;
}
@@ -89,7 +249,10 @@ bool PasteBookmarkManagerFunction::RunImpl() {
bool CanPasteBookmarkManagerFunction::RunImpl() {
BookmarkModel* model = profile()->GetBookmarkModel();
const BookmarkNode* parent_node = GetNodeFromArguments(model, args_.get());
- EXTENSION_FUNCTION_VALIDATE(parent_node);
+ if (!parent_node) {
+ error_ = keys::kNoParentError;
+ return false;
+ }
bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node);
result_.reset(Value::CreateBooleanValue(can_paste));
SendResponse(true);
@@ -160,7 +323,10 @@ void ExportBookmarksFunction::FileSelected(const FilePath& path,
bool SortChildrenBookmarkManagerFunction::RunImpl() {
BookmarkModel* model = profile()->GetBookmarkModel();
const BookmarkNode* parent_node = GetNodeFromArguments(model, args_.get());
- EXTENSION_FUNCTION_VALIDATE(parent_node);
+ if (!parent_node) {
+ error_ = keys::kNoParentError;
+ return false;
+ }
model->SortChildren(parent_node);
return true;
}
@@ -223,3 +389,58 @@ bool BookmarkManagerGetStringsFunction::RunImpl() {
SendResponse(true);
return true;
}
+
+bool StartDragBookmarkManagerFunction::RunImpl() {
+ BookmarkModel* model = profile()->GetBookmarkModel();
+ std::vector<const BookmarkNode*> nodes;
+ EXTENSION_FUNCTION_VALIDATE(
+ GetNodesFromArguments(model, args_as_list(), &nodes));
+
+ bookmark_utils::DragBookmarks(profile(), nodes,
+ dispatcher()->GetExtensionDOMUI()->tab_contents()->GetNativeView());
+
+ return true;
+}
+
+bool DropBookmarkManagerFunction::RunImpl() {
+ BookmarkModel* model = profile()->GetBookmarkModel();
+
+ // TODO(arv): The arguments change between a list and a value depending on the
+ // parameters. See http://crbug.com/36301
+ int64 id;
+ std::string id_string;
+ if (args_->IsType(Value::TYPE_STRING)) {
+ EXTENSION_FUNCTION_VALIDATE(args_->GetAsString(&id_string));
+ } else {
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_LIST));
+ EXTENSION_FUNCTION_VALIDATE(args_as_list()->GetString(0, &id_string));
+ }
+ if (!StringToInt64(id_string, &id)) {
+ error_ = keys::kInvalidIdError;
+ return false;
+ }
+
+ const BookmarkNode* drop_parent = model->GetNodeByID(id);
+ if (!drop_parent) {
+ error_ = keys::kNoParentError;
+ return false;
+ }
+
+ int drop_index;
+ if (args_as_list()->GetSize() == 2)
+ EXTENSION_FUNCTION_VALIDATE(args_as_list()->GetInteger(1, &drop_index));
+ else
+ drop_index = drop_parent->GetChildCount();
+
+ ExtensionBookmarkManagerEventRouter* router = dispatcher()->
+ GetExtensionDOMUI()->extension_bookmark_manager_event_router();
+
+ DCHECK(router);
+
+ bookmark_utils::PerformBookmarkDrop(profile(), *router->GetBookmarkDragData(),
+ drop_parent, drop_index);
+
+ router->ClearBookmarkDragData();
+ SendResponse(true);
+ return true;
+}
diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.h b/chrome/browser/extensions/extension_bookmark_manager_api.h
index aab4422..3ab9964 100644
--- a/chrome/browser/extensions/extension_bookmark_manager_api.h
+++ b/chrome/browser/extensions/extension_bookmark_manager_api.h
@@ -5,11 +5,50 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARK_MANAGER_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARK_MANAGER_API_H_
+#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/extensions/extension_bookmarks_module.h"
#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/shell_dialogs.h"
class BookmarkNode;
+class ListValue;
+class Profile;
+class TabContents;
+
+// Class that handles the chrome.experimental.bookmarkManager events.
+class ExtensionBookmarkManagerEventRouter
+ : public RenderViewHostDelegate::BookmarkDrag {
+ public:
+ ExtensionBookmarkManagerEventRouter(Profile* profile,
+ TabContents* tab_contents);
+ virtual ~ExtensionBookmarkManagerEventRouter();
+
+ // RenderViewHostDelegate::BookmarkDrag interface
+ virtual void OnDragEnter(const DragData* data);
+ virtual void OnDragOver(const DragData* data);
+ virtual void OnDragLeave(const DragData* data);
+ virtual void OnDrop(const DragData* data);
+
+ // The bookmark drag and drop data. This gets set after a drop was done on
+ // the page. This returns NULL if no data is available.
+ const BookmarkDragData* GetBookmarkDragData();
+
+ // Clears the drag and drop data.
+ void ClearBookmarkDragData();
+
+ private:
+ // Helper to actually dispatch an event to extension listeners.
+ void DispatchEvent(const char* event_name, const ListValue* args);
+
+ void DispatchDragEvent(const DragData* data, const char* event_name);
+
+ Profile* profile_;
+ TabContents* tab_contents_;
+ BookmarkDragData bookmark_drag_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionBookmarkManagerEventRouter);
+};
class ClipboardBookmarkManagerFunction : public BookmarksFunction {
protected:
@@ -34,9 +73,9 @@ class CutBookmarkManagerFunction : public ClipboardBookmarkManagerFunction {
DECLARE_EXTENSION_FUNCTION_NAME("experimental.bookmarkManager.cut");
};
-class PasteBookmarkManagerFunction : public ClipboardBookmarkManagerFunction {
+class PasteBookmarkManagerFunction : public BookmarksFunction {
public:
- // Override ClipboardBookmarkManagerFunction.
+ // Override BookmarksFunction.
virtual bool RunImpl();
private:
@@ -44,9 +83,9 @@ class PasteBookmarkManagerFunction : public ClipboardBookmarkManagerFunction {
};
class CanPasteBookmarkManagerFunction
- : public ClipboardBookmarkManagerFunction {
+ : public BookmarksFunction {
public:
- // Override ClipboardBookmarkManagerFunction.
+ // Override BookmarksFunction.
virtual bool RunImpl();
private:
@@ -87,9 +126,9 @@ class ExportBookmarksFunction : public BookmarkManagerIOFunction {
};
class SortChildrenBookmarkManagerFunction
- : public ClipboardBookmarkManagerFunction {
+ : public BookmarksFunction {
public:
- // Override ClipboardBookmarkManagerFunction.
+ // Override BookmarksFunction.
virtual bool RunImpl();
private:
@@ -106,4 +145,22 @@ class BookmarkManagerGetStringsFunction : public AsyncExtensionFunction {
DECLARE_EXTENSION_FUNCTION_NAME("experimental.bookmarkManager.getStrings");
};
+class StartDragBookmarkManagerFunction
+ : public BookmarksFunction {
+ public:
+ // Override BookmarksFunction.
+ virtual bool RunImpl();
+
+ private:
+ DECLARE_EXTENSION_FUNCTION_NAME("experimental.bookmarkManager.startDrag");
+};
+
+class DropBookmarkManagerFunction : public BookmarksFunction {
+ public:
+ virtual bool RunImpl();
+
+ private:
+ DECLARE_EXTENSION_FUNCTION_NAME("experimental.bookmarkManager.drop");
+};
+
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARK_MANAGER_API_H_
diff --git a/chrome/browser/extensions/extension_bookmarks_module_constants.cc b/chrome/browser/extensions/extension_bookmarks_module_constants.cc
index 9440f06..3e20f3d 100644
--- a/chrome/browser/extensions/extension_bookmarks_module_constants.cc
+++ b/chrome/browser/extensions/extension_bookmarks_module_constants.cc
@@ -18,6 +18,9 @@ const wchar_t kChildIdsKey[] = L"childIds";
const wchar_t kRecursiveKey[] = L"recursive";
const wchar_t kDateAddedKey[] = L"dateAdded";
const wchar_t kDateGroupModifiedKey[] = L"dateGroupModified";
+// TODO(arv): Move bookmark manager related constants out of this file.
+const wchar_t kSameProfileKey[] = L"sameProfile";
+const wchar_t kElementsKey[] = L"elements";
const char kNoNodeError[] = "Can't find bookmark for id.";
const char kNoParentError[] = "Can't find parent bookmark for id.";
@@ -33,8 +36,15 @@ const char kOnBookmarkRemoved[] = "bookmarks.onRemoved";
const char kOnBookmarkChanged[] = "bookmarks.onChanged";
const char kOnBookmarkMoved[] = "bookmarks.onMoved";
const char kOnBookmarkChildrenReordered[] = "bookmarks.onChildrenReordered";
+// TODO(arv): Move bookmark manager related constants out of this file.
const char kOnBookmarkImportBegan[] =
"experimental.bookmarkManager.onImportBegan";
const char kOnBookmarkImportEnded[] =
"experimental.bookmarkManager.onImportEnded";
+const char kOnBookmarkDragEnter[] =
+ "experimental.bookmarkManager.onDragEnter";
+const char kOnBookmarkDragLeave[] =
+ "experimental.bookmarkManager.onDragLeave";
+const char kOnBookmarkDrop[] =
+ "experimental.bookmarkManager.onDrop";
} // namespace extension_bookmarks_module_constants
diff --git a/chrome/browser/extensions/extension_bookmarks_module_constants.h b/chrome/browser/extensions/extension_bookmarks_module_constants.h
index 7214e80..3635918 100644
--- a/chrome/browser/extensions/extension_bookmarks_module_constants.h
+++ b/chrome/browser/extensions/extension_bookmarks_module_constants.h
@@ -22,6 +22,9 @@ extern const wchar_t kChildIdsKey[];
extern const wchar_t kRecursiveKey[];
extern const wchar_t kDateAddedKey[];
extern const wchar_t kDateGroupModifiedKey[];
+// TODO(arv): Move bookmark manager related constants out of this file.
+extern const wchar_t kSameProfileKey[];
+extern const wchar_t kElementsKey[];
// Errors.
extern const char kNoNodeError[];
@@ -38,8 +41,12 @@ extern const char kOnBookmarkRemoved[];
extern const char kOnBookmarkChanged[];
extern const char kOnBookmarkMoved[];
extern const char kOnBookmarkChildrenReordered[];
+// TODO(arv): Move bookmark manager related constants out of this file.
extern const char kOnBookmarkImportBegan[];
extern const char kOnBookmarkImportEnded[];
+extern const char kOnBookmarkDragEnter[];
+extern const char kOnBookmarkDragLeave[];
+extern const char kOnBookmarkDrop[];
}; // namespace extension_bookmarks_module_constants
diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc
index d3da8cc..de2d13b 100644
--- a/chrome/browser/extensions/extension_dom_ui.cc
+++ b/chrome/browser/extensions/extension_dom_ui.cc
@@ -7,12 +7,14 @@
#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/extensions/extension_bookmark_manager_api.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/bindings_policy.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
namespace {
@@ -48,12 +50,22 @@ void ExtensionDOMUI::ResetExtensionFunctionDispatcher(
new ExtensionFunctionDispatcher(render_view_host, this, url));
}
+void ExtensionDOMUI::ResetExtensionBookmarkManagerEventRouter() {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalExtensionApis)) {
+ extension_bookmark_manager_event_router_.reset(
+ new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents()));
+ }
+}
+
void ExtensionDOMUI::RenderViewCreated(RenderViewHost* render_view_host) {
ResetExtensionFunctionDispatcher(render_view_host);
+ ResetExtensionBookmarkManagerEventRouter();
}
void ExtensionDOMUI::RenderViewReused(RenderViewHost* render_view_host) {
ResetExtensionFunctionDispatcher(render_view_host);
+ ResetExtensionBookmarkManagerEventRouter();
}
void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message,
diff --git a/chrome/browser/extensions/extension_dom_ui.h b/chrome/browser/extensions/extension_dom_ui.h
index c7d2b97..59a89a8 100644
--- a/chrome/browser/extensions/extension_dom_ui.h
+++ b/chrome/browser/extensions/extension_dom_ui.h
@@ -9,6 +9,7 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/dom_ui/dom_ui.h"
+#include "chrome/browser/extensions/extension_bookmark_manager_api.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_popup_host.h"
#include "chrome/common/extensions/extension.h"
@@ -49,6 +50,11 @@ class ExtensionDOMUI
virtual Profile* GetProfile();
virtual gfx::NativeView GetNativeViewOfHost();
+ virtual ExtensionBookmarkManagerEventRouter*
+ extension_bookmark_manager_event_router() {
+ return extension_bookmark_manager_event_router_.get();
+ }
+
// BrowserURLHandler
static bool HandleChromeURLOverride(GURL* url, Profile* profile);
@@ -56,9 +62,9 @@ class ExtensionDOMUI
// Page names are the keys, and chrome-extension: URLs are the values.
// (e.g. { "newtab": "chrome-extension://<id>/my_new_tab.html" }
static void RegisterChromeURLOverrides(Profile* profile,
- const Extension::URLOverrideMap& overrides);
+ const Extension::URLOverrideMap& overrides);
static void UnregisterChromeURLOverrides(Profile* profile,
- const Extension::URLOverrideMap& overrides);
+ const Extension::URLOverrideMap& overrides);
static void UnregisterChromeURLOverride(const std::string& page,
Profile* profile,
Value* override);
@@ -79,7 +85,12 @@ class ExtensionDOMUI
// right one, as well as being linked to the correct URL.
void ResetExtensionFunctionDispatcher(RenderViewHost* render_view_host);
+ void ResetExtensionBookmarkManagerEventRouter();
+
scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
+
+ scoped_ptr<ExtensionBookmarkManagerEventRouter>
+ extension_bookmark_manager_event_router_;
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_DOM_UI_H_
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index d39bd07..69e4d54 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -145,6 +145,8 @@ void FactoryRegistry::ResetFunctions() {
RegisterFunction<ExportBookmarksFunction>();
RegisterFunction<SortChildrenBookmarkManagerFunction>();
RegisterFunction<BookmarkManagerGetStringsFunction>();
+ RegisterFunction<StartDragBookmarkManagerFunction>();
+ RegisterFunction<DropBookmarkManagerFunction>();
// History
RegisterFunction<AddUrlHistoryFunction>();
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.cc b/chrome/browser/renderer_host/render_view_host_delegate.cc
index ac54b26..620e156 100644
--- a/chrome/browser/renderer_host/render_view_host_delegate.cc
+++ b/chrome/browser/renderer_host/render_view_host_delegate.cc
@@ -57,6 +57,11 @@ RenderViewHostDelegate::GetAutoFillDelegate() {
return NULL;
}
+RenderViewHostDelegate::BookmarkDrag*
+RenderViewHostDelegate::GetBookmarkDragDelegate() {
+ return NULL;
+}
+
const GURL& RenderViewHostDelegate::GetURL() const {
return GURL::EmptyGURL();
}
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h
index 8d6461d..f4e088e 100644
--- a/chrome/browser/renderer_host/render_view_host_delegate.h
+++ b/chrome/browser/renderer_host/render_view_host_delegate.h
@@ -16,12 +16,14 @@
#include "third_party/WebKit/WebKit/chromium/public/WebDragOperation.h"
#include "webkit/glue/window_open_disposition.h"
+struct BookmarkDragData;
struct ContextMenuParams;
class FilePath;
struct FormData;
class GURL;
struct NativeWebKeyboardEvent;
class NavigationEntry;
+class OSExchangeData;
class Profile;
struct RendererPreferences;
class RenderProcessHost;
@@ -414,6 +416,28 @@ class RenderViewHostDelegate {
const string16& label) = 0;
};
+ // BookmarkDrag --------------------------------------------------------------
+ // Interface for forwarding bookmark drag and drop to extenstions.
+
+ class BookmarkDrag {
+ public:
+
+#if defined(TOOLKIT_VIEWS)
+ typedef OSExchangeData DragData;
+#elif defined(OS_LINUX)
+ // TODO(arv): GtkSelectionData?
+ class DragData {};
+#else
+ // TODO(arv): NSDraggingInfo?
+ class DragData {};
+#endif
+
+ virtual void OnDragEnter(const DragData* data) = 0;
+ virtual void OnDragOver(const DragData* data) = 0;
+ virtual void OnDragLeave(const DragData* data) = 0;
+ virtual void OnDrop(const DragData* data) = 0;
+ };
+
// ---------------------------------------------------------------------------
// Returns the current delegate associated with a feature. May return NULL if
@@ -427,6 +451,7 @@ class RenderViewHostDelegate {
virtual FavIcon* GetFavIconDelegate();
virtual FormFieldHistory* GetFormFieldHistoryDelegate();
virtual AutoFill* GetAutoFillDelegate();
+ virtual BookmarkDrag* GetBookmarkDragDelegate();
// Gets the URL that is currently being displayed, if there is one.
virtual const GURL& GetURL() const;
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 82ec6f0..e78d2b2 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -2067,6 +2067,15 @@ RenderViewHostDelegate::AutoFill* TabContents::GetAutoFillDelegate() {
return autofill_manager_.get();
}
+RenderViewHostDelegate::BookmarkDrag* TabContents::GetBookmarkDragDelegate() {
+ return bookmark_drag_;
+}
+
+void TabContents::SetBookmarkDragDelegate(
+ RenderViewHostDelegate::BookmarkDrag* bookmark_drag) {
+ bookmark_drag_ = bookmark_drag;
+}
+
RendererPreferences TabContents::GetRendererPrefs(Profile* profile) const {
return renderer_preferences_;
}
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index 1553032..1ee1126 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -663,6 +663,16 @@ class TabContents : public PageNavigator,
virtual TabContents* AsTabContents() { return this; }
virtual ExtensionHost* AsExtensionHost() { return NULL; }
+ // The BookmarkDragDelegate is used to forward bookmark drag and drop events
+ // to extensions.
+ virtual RenderViewHostDelegate::BookmarkDrag* GetBookmarkDragDelegate();
+
+ // It is up to callers to call SetBookmarkDragDelegate(NULL) when
+ // |bookmark_drag| is deleted since this class does not take ownership of
+ // |bookmark_drag|.
+ virtual void SetBookmarkDragDelegate(
+ RenderViewHostDelegate::BookmarkDrag* bookmark_drag);
+
private:
friend class NavigationController;
// Used to access the child_windows_ (ConstrainedWindowList) for testing
@@ -1012,6 +1022,9 @@ class TabContents : public PageNavigator,
// PluginInstaller, lazily created.
scoped_ptr<PluginInstaller> plugin_installer_;
+ // Handles drag and drop event forwarding to extensions.
+ BookmarkDrag* bookmark_drag_;
+
// Handles downloading favicons.
FavIconHelper fav_icon_helper_;
diff --git a/chrome/browser/tab_contents/web_drop_target_win.cc b/chrome/browser/tab_contents/web_drop_target_win.cc
index ed2c7c6..578d9a9 100644
--- a/chrome/browser/tab_contents/web_drop_target_win.cc
+++ b/chrome/browser/tab_contents/web_drop_target_win.cc
@@ -118,6 +118,13 @@ DWORD WebDropTarget::OnDragEnter(IDataObject* data_object,
gfx::Point(cursor_position.x, cursor_position.y),
WebDragOperationCopy); // FIXME(snej): Send actual operation
+ // This is non-null if tab_contents_ is showing an ExtensionDOMUI with
+ // support for (at the moment experimental) drag and drop extensions.
+ if (tab_contents_->GetBookmarkDragDelegate()) {
+ OSExchangeData os_exchange_data(new OSExchangeDataProviderWin(data_object));
+ tab_contents_->GetBookmarkDragDelegate()->OnDragEnter(&os_exchange_data);
+ }
+
// We lie here and always return a DROPEFFECT because we don't want to
// wait for the IPC call to return.
return GetPreferredDropEffect(effect);
@@ -141,6 +148,11 @@ DWORD WebDropTarget::OnDragOver(IDataObject* data_object,
gfx::Point(cursor_position.x, cursor_position.y),
WebDragOperationCopy); // FIXME(snej): Send actual operation
+ if (tab_contents_->GetBookmarkDragDelegate()) {
+ OSExchangeData os_exchange_data(new OSExchangeDataProviderWin(data_object));
+ tab_contents_->GetBookmarkDragDelegate()->OnDragOver(&os_exchange_data);
+ }
+
if (!is_drop_target_)
return DROPEFFECT_NONE;
@@ -157,6 +169,11 @@ void WebDropTarget::OnDragLeave(IDataObject* data_object) {
} else {
tab_contents_->render_view_host()->DragTargetDragLeave();
}
+
+ if (tab_contents_->GetBookmarkDragDelegate()) {
+ OSExchangeData os_exchange_data(new OSExchangeDataProviderWin(data_object));
+ tab_contents_->GetBookmarkDragDelegate()->OnDragLeave(&os_exchange_data);
+ }
}
DWORD WebDropTarget::OnDrop(IDataObject* data_object,
@@ -179,6 +196,11 @@ DWORD WebDropTarget::OnDrop(IDataObject* data_object,
gfx::Point(client_pt.x, client_pt.y),
gfx::Point(cursor_position.x, cursor_position.y));
+ if (tab_contents_->GetBookmarkDragDelegate()) {
+ OSExchangeData os_exchange_data(new OSExchangeDataProviderWin(data_object));
+ tab_contents_->GetBookmarkDragDelegate()->OnDrop(&os_exchange_data);
+ }
+
current_rvh_ = NULL;
// We lie and always claim that the drop operation didn't happen because we
diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json
index 3962f7a..3d6f734 100755
--- a/chrome/common/extensions/api/extension_api.json
+++ b/chrome/common/extensions/api/extension_api.json
@@ -1955,7 +1955,47 @@
{
"namespace": "experimental.bookmarkManager",
"nodoc": true,
- "types": [],
+ "types": [
+ {
+ "id": "BookmarkDragDataElement",
+ "nodoc": true,
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "optional": true,
+ "description": "The ID of the bookmark. This is only provided if the data is from the same profile."
+ },
+ "parentId": {
+ "type": "string",
+ "optional": true,
+ "description": "The ID of the parent of the bookmark. This is only provided if the data is from the same profile."
+ },
+ "title": {"type": "string"},
+ "url": {
+ "type": "string",
+ "optional": true
+ },
+ "children": {
+ "type": "array",
+ "items": {"$ref": "BookmarkDragDataElement"}
+ }
+ }
+ },
+ {
+ "id": "BookmarkDragData",
+ "nodoc": true,
+ "type": "object",
+ "description": "Information about the drag and drop data for use with drag and drop events.",
+ "properties": {
+ "sameProfile": {"type": "boolean"},
+ "elements": {
+ "type": "array",
+ "items": {"$ref": "BookmarkDragDataElement"}
+ }
+ }
+ }
+ ],
"functions": [
{
"name": "copy",
@@ -2056,6 +2096,41 @@
]
}
]
+ },
+ {
+ "name": "startDrag",
+ "type": "function",
+ "description": "Begins dragging a set of bookmarks",
+ "nodoc": "true",
+ "parameters": [
+ {
+ "name": "idList",
+ "description": "An array of string-valued ids",
+ "type": "array",
+ "items": {"type": "string"},
+ "minItems": 1
+ }
+ ]
+ },
+ {
+ "name": "drop",
+ "type": "function",
+ "description": "Performs the drop action of the drag and drop session",
+ "nodoc": "true",
+ "parameters": [
+ {
+ "name": "parentId",
+ "description": "The ID of the folder that the drop was made",
+ "type": "string"
+ },
+ {
+ "name": "index",
+ "description": "The index of the position to drop at. If left out the dropped items will be placed at the end of the existing children",
+ "type": "integer",
+ "minimum": 0,
+ "optional": true
+ }
+ ]
}
],
"events": [
@@ -2074,8 +2149,31 @@
"parameters": [
{}
]
+ },
+ {
+ "name": "onDragEnter",
+ "type": "function",
+ "description": "Fired when dragging bookmarks over the document",
+ "parameters": [
+ {"$ref": "BookmarkDragData"}
+ ]
+ },
+ {
+ "name": "onDragLeave",
+ "type": "function",
+ "description": "Fired when the drag and drop leaves the document",
+ "parameters": [
+ {"$ref": "BookmarkDragData"}
+ ]
+ },
+ {
+ "name": "onDrop",
+ "type": "function",
+ "description": "Fired when the user drops bookmarks on the document",
+ "parameters": [
+ {"$ref": "BookmarkDragData"}
+ ]
}
-
]
},
{