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