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