bookmark_drag_drop_views.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/message_loop/message_loop.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_node_data.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/pref_names.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "components/user_prefs/user_prefs.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/dragdrop/drag_drop_types.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/dragdrop/os_exchange_data.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/events/event.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/drag_utils.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/widget/widget.h"
197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chrome {
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DragBookmarks(Profile* profile,
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   const std::vector<const BookmarkNode*>& nodes,
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   gfx::NativeView view,
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   ui::DragDropTypes::DragEventSource source) {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!nodes.empty());
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Set up our OLE machinery
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::OSExchangeData data;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BookmarkNodeData drag_data(nodes);
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  drag_data.Write(profile, &data);
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Allow nested message loop so we get DnD events as we drag this around.
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool was_nested = base::MessageLoop::current()->IsNested();
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessageLoop::current()->SetNestableTasksAllowed(true);
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int operation = ui::DragDropTypes::DRAG_COPY |
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  ui::DragDropTypes::DRAG_MOVE |
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  ui::DragDropTypes::DRAG_LINK;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::Widget* widget = views::Widget::GetWidgetForNativeView(view);
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (widget) {
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    widget->RunShellDrag(NULL, data, gfx::Point(), operation, source);
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We hit this case when we're using WebContentsViewWin or
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // WebContentsViewAura, instead of WebContentsViewViews.
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    views::RunShellDrag(view, data, gfx::Point(), operation, source);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::MessageLoop::current()->SetNestableTasksAllowed(was_nested);
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int GetBookmarkDragOperation(content::BrowserContext* browser_context,
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const BookmarkNode* node) {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrefService* prefs = user_prefs::UserPrefs::Get(browser_context);
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int move = ui::DragDropTypes::DRAG_MOVE;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!prefs->GetBoolean(prefs::kEditBookmarksEnabled))
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    move = ui::DragDropTypes::DRAG_NONE;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (node->is_url())
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK | move;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ui::DragDropTypes::DRAG_COPY | move;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int GetPreferredBookmarkDropOperation(int source_operations, int operations) {
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int common_ops = (source_operations & operations);
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!common_ops)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ui::DragDropTypes::DRAG_NONE;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (ui::DragDropTypes::DRAG_COPY & common_ops)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ui::DragDropTypes::DRAG_COPY;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (ui::DragDropTypes::DRAG_LINK & common_ops)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ui::DragDropTypes::DRAG_LINK;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (ui::DragDropTypes::DRAG_MOVE & common_ops)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ui::DragDropTypes::DRAG_MOVE;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ui::DragDropTypes::DRAG_NONE;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int GetBookmarkDropOperation(Profile* profile,
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const ui::DropTargetEvent& event,
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const BookmarkNodeData& data,
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const BookmarkNode* parent,
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             int index) {
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data.IsFromProfile(profile) && data.size() > 1)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Currently only accept one dragged node at a time.
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ui::DragDropTypes::DRAG_NONE;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!IsValidBookmarkDropLocation(profile, data, parent, index))
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ui::DragDropTypes::DRAG_NONE;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data.GetFirstNode(profile))
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // User is dragging from this profile: move.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ui::DragDropTypes::DRAG_MOVE;
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // User is dragging from another app, copy.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return GetPreferredBookmarkDropOperation(event.source_operations(),
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK);
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsValidBookmarkDropLocation(Profile* profile,
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 const BookmarkNodeData& data,
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 const BookmarkNode* drop_parent,
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 int index) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!drop_parent->is_folder()) {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NOTREACHED();
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!data.is_valid())
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (data.IsFromProfile(profile)) {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<const BookmarkNode*> nodes = data.GetNodes(profile);
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < nodes.size(); ++i) {
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Don't allow the drop if the user is attempting to drop on one of the
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // nodes being dragged.
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const BookmarkNode* node = nodes[i];
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int node_index = (drop_parent == node->parent()) ?
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          drop_parent->GetIndexOf(nodes[i]) : -1;
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (node_index != -1 && (index == node_index || index == node_index + 1))
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // drop_parent can't accept a child that is an ancestor.
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (drop_parent->HasAncestor(node))
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // From the same profile, always accept.
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chrome
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)