From ced90ae1159e8967837cd13b9155956467a811f9 Mon Sep 17 00:00:00 2001 From: "arv@chromium.org" Date: Sat, 20 Feb 2010 02:06:16 +0000 Subject: 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 --- chrome/browser/bookmarks/bookmark_drag_data.cc | 5 + chrome/browser/bookmarks/bookmark_drag_data.h | 3 + chrome/browser/bookmarks/bookmark_utils.cc | 48 ++++- chrome/browser/bookmarks/bookmark_utils.h | 5 + .../extensions/extension_bookmark_manager_api.cc | 233 ++++++++++++++++++++- .../extensions/extension_bookmark_manager_api.h | 69 +++++- .../extension_bookmarks_module_constants.cc | 10 + .../extension_bookmarks_module_constants.h | 7 + chrome/browser/extensions/extension_dom_ui.cc | 12 ++ chrome/browser/extensions/extension_dom_ui.h | 15 +- .../extensions/extension_function_dispatcher.cc | 2 + .../renderer_host/render_view_host_delegate.cc | 5 + .../renderer_host/render_view_host_delegate.h | 25 +++ chrome/browser/tab_contents/tab_contents.cc | 9 + chrome/browser/tab_contents/tab_contents.h | 13 ++ chrome/browser/tab_contents/web_drop_target_win.cc | 22 ++ chrome/common/extensions/api/extension_api.json | 102 ++++++++- 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 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& 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& 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 + #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 - 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 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 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 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:///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 extension_function_dispatcher_; + + scoped_ptr + 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(); RegisterFunction(); RegisterFunction(); + RegisterFunction(); + RegisterFunction(); // History RegisterFunction(); 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 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"} + ] } - ] }, { -- cgit v1.1