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