bookmark_drag_drop_views.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
1// Copyright 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.h" 6 7#include "base/message_loop/message_loop.h" 8#include "base/prefs/pref_service.h" 9#include "chrome/browser/bookmarks/bookmark_model.h" 10#include "chrome/browser/bookmarks/bookmark_node_data.h" 11#include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h" 12#include "chrome/common/pref_names.h" 13#include "components/user_prefs/user_prefs.h" 14#include "ui/base/dragdrop/drag_drop_types.h" 15#include "ui/base/dragdrop/os_exchange_data.h" 16#include "ui/events/event.h" 17#include "ui/views/drag_utils.h" 18#include "ui/views/widget/widget.h" 19 20namespace chrome { 21 22void DragBookmarks(Profile* profile, 23 const std::vector<const BookmarkNode*>& nodes, 24 gfx::NativeView view) { 25 DCHECK(!nodes.empty()); 26 27 // Set up our OLE machinery 28 ui::OSExchangeData data; 29 BookmarkNodeData drag_data(nodes); 30 drag_data.Write(profile, &data); 31 32 // Allow nested message loop so we get DnD events as we drag this around. 33 bool was_nested = base::MessageLoop::current()->IsNested(); 34 base::MessageLoop::current()->SetNestableTasksAllowed(true); 35 36 int operation = ui::DragDropTypes::DRAG_COPY | 37 ui::DragDropTypes::DRAG_MOVE | 38 ui::DragDropTypes::DRAG_LINK; 39 views::Widget* widget = views::Widget::GetWidgetForNativeView(view); 40 // TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below. 41 if (widget) { 42 widget->RunShellDrag(NULL, data, gfx::Point(), operation, 43 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); 44 } else { 45 // We hit this case when we're using WebContentsViewWin or 46 // WebContentsViewAura, instead of WebContentsViewViews. 47 views::RunShellDrag(view, data, gfx::Point(), operation, 48 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); 49 } 50 51 base::MessageLoop::current()->SetNestableTasksAllowed(was_nested); 52} 53 54int GetBookmarkDragOperation(content::BrowserContext* browser_context, 55 const BookmarkNode* node) { 56 PrefService* prefs = user_prefs::UserPrefs::Get(browser_context); 57 58 int move = ui::DragDropTypes::DRAG_MOVE; 59 if (!prefs->GetBoolean(prefs::kEditBookmarksEnabled)) 60 move = ui::DragDropTypes::DRAG_NONE; 61 if (node->is_url()) 62 return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK | move; 63 return ui::DragDropTypes::DRAG_COPY | move; 64} 65 66int GetPreferredBookmarkDropOperation(int source_operations, int operations) { 67 int common_ops = (source_operations & operations); 68 if (!common_ops) 69 return ui::DragDropTypes::DRAG_NONE; 70 if (ui::DragDropTypes::DRAG_COPY & common_ops) 71 return ui::DragDropTypes::DRAG_COPY; 72 if (ui::DragDropTypes::DRAG_LINK & common_ops) 73 return ui::DragDropTypes::DRAG_LINK; 74 if (ui::DragDropTypes::DRAG_MOVE & common_ops) 75 return ui::DragDropTypes::DRAG_MOVE; 76 return ui::DragDropTypes::DRAG_NONE; 77} 78 79int GetBookmarkDropOperation(Profile* profile, 80 const ui::DropTargetEvent& event, 81 const BookmarkNodeData& data, 82 const BookmarkNode* parent, 83 int index) { 84 if (data.IsFromProfile(profile) && data.size() > 1) 85 // Currently only accept one dragged node at a time. 86 return ui::DragDropTypes::DRAG_NONE; 87 88 if (!IsValidBookmarkDropLocation(profile, data, parent, index)) 89 return ui::DragDropTypes::DRAG_NONE; 90 91 if (data.GetFirstNode(profile)) 92 // User is dragging from this profile: move. 93 return ui::DragDropTypes::DRAG_MOVE; 94 95 // User is dragging from another app, copy. 96 return GetPreferredBookmarkDropOperation(event.source_operations(), 97 ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK); 98} 99 100bool IsValidBookmarkDropLocation(Profile* profile, 101 const BookmarkNodeData& data, 102 const BookmarkNode* drop_parent, 103 int index) { 104 if (!drop_parent->is_folder()) { 105 NOTREACHED(); 106 return false; 107 } 108 109 if (!data.is_valid()) 110 return false; 111 112 if (data.IsFromProfile(profile)) { 113 std::vector<const BookmarkNode*> nodes = data.GetNodes(profile); 114 for (size_t i = 0; i < nodes.size(); ++i) { 115 // Don't allow the drop if the user is attempting to drop on one of the 116 // nodes being dragged. 117 const BookmarkNode* node = nodes[i]; 118 int node_index = (drop_parent == node->parent()) ? 119 drop_parent->GetIndexOf(nodes[i]) : -1; 120 if (node_index != -1 && (index == node_index || index == node_index + 1)) 121 return false; 122 123 // drop_parent can't accept a child that is an ancestor. 124 if (drop_parent->HasAncestor(node)) 125 return false; 126 } 127 return true; 128 } 129 // From the same profile, always accept. 130 return true; 131} 132 133} // namespace chrome 134