Home | History | Annotate | Download | only in bookmarks
      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
    163