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