Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / bookmarks / bookmark_drag_drop_views.cc
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
23 using bookmarks::BookmarkNodeData;
24
25 namespace chrome {
26
27 void 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
60 int 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(bookmarks::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
76 int 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
89 int 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
124 bool 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