1 // Copyright (c) 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 "ui/views/widget/drop_helper.h" 6 7 #include "ui/base/dragdrop/drag_drop_types.h" 8 #include "ui/views/view.h" 9 #include "ui/views/widget/widget.h" 10 11 namespace views { 12 13 DropHelper::DropHelper(View* root_view) 14 : root_view_(root_view), 15 target_view_(NULL), 16 deepest_view_(NULL) { 17 } 18 19 DropHelper::~DropHelper() { 20 } 21 22 void DropHelper::ResetTargetViewIfEquals(View* view) { 23 if (target_view_ == view) 24 target_view_ = NULL; 25 if (deepest_view_ == view) 26 deepest_view_ = NULL; 27 } 28 29 int DropHelper::OnDragOver(const OSExchangeData& data, 30 const gfx::Point& root_view_location, 31 int drag_operation) { 32 View* view = CalculateTargetViewImpl(root_view_location, data, true, 33 &deepest_view_); 34 35 if (view != target_view_) { 36 // Target changed notify old drag exited, then new drag entered. 37 NotifyDragExit(); 38 target_view_ = view; 39 NotifyDragEntered(data, root_view_location, drag_operation); 40 } 41 42 return NotifyDragOver(data, root_view_location, drag_operation); 43 } 44 45 void DropHelper::OnDragExit() { 46 NotifyDragExit(); 47 deepest_view_ = target_view_ = NULL; 48 } 49 50 int DropHelper::OnDrop(const OSExchangeData& data, 51 const gfx::Point& root_view_location, 52 int drag_operation) { 53 View* drop_view = target_view_; 54 deepest_view_ = target_view_ = NULL; 55 if (!drop_view) 56 return ui::DragDropTypes::DRAG_NONE; 57 58 if (drag_operation == ui::DragDropTypes::DRAG_NONE) { 59 drop_view->OnDragExited(); 60 return ui::DragDropTypes::DRAG_NONE; 61 } 62 63 gfx::Point view_location(root_view_location); 64 View* root_view = drop_view->GetWidget()->GetRootView(); 65 View::ConvertPointToTarget(root_view, drop_view, &view_location); 66 ui::DropTargetEvent drop_event(data, view_location, view_location, 67 drag_operation); 68 return drop_view->OnPerformDrop(drop_event); 69 } 70 71 View* DropHelper::CalculateTargetView( 72 const gfx::Point& root_view_location, 73 const OSExchangeData& data, 74 bool check_can_drop) { 75 return CalculateTargetViewImpl(root_view_location, data, check_can_drop, 76 NULL); 77 } 78 79 View* DropHelper::CalculateTargetViewImpl( 80 const gfx::Point& root_view_location, 81 const OSExchangeData& data, 82 bool check_can_drop, 83 View** deepest_view) { 84 View* view = root_view_->GetEventHandlerForPoint(root_view_location); 85 if (view == deepest_view_) { 86 // The view the mouse is over hasn't changed; reuse the target. 87 return target_view_; 88 } 89 if (deepest_view) 90 *deepest_view = view; 91 // TODO(sky): for the time being these are separate. Once I port chrome menu 92 // I can switch to the #else implementation and nuke the OS_WIN 93 // implementation. 94 #if defined(OS_WIN) 95 // View under mouse changed, which means a new view may want the drop. 96 // Walk the tree, stopping at target_view_ as we know it'll accept the 97 // drop. 98 while (view && view != target_view_ && 99 (!view->enabled() || !view->CanDrop(data))) { 100 view = view->parent(); 101 } 102 #else 103 int formats = 0; 104 std::set<OSExchangeData::CustomFormat> custom_formats; 105 while (view && view != target_view_) { 106 if (view->enabled() && 107 view->GetDropFormats(&formats, &custom_formats) && 108 data.HasAnyFormat(formats, custom_formats) && 109 (!check_can_drop || view->CanDrop(data))) { 110 // Found the view. 111 return view; 112 } 113 formats = 0; 114 custom_formats.clear(); 115 view = view->parent(); 116 } 117 #endif 118 return view; 119 } 120 121 void DropHelper::NotifyDragEntered(const OSExchangeData& data, 122 const gfx::Point& root_view_location, 123 int drag_operation) { 124 if (!target_view_) 125 return; 126 127 gfx::Point target_view_location(root_view_location); 128 View::ConvertPointToTarget(root_view_, target_view_, &target_view_location); 129 ui::DropTargetEvent enter_event(data, 130 target_view_location, 131 target_view_location, 132 drag_operation); 133 target_view_->OnDragEntered(enter_event); 134 } 135 136 int DropHelper::NotifyDragOver(const OSExchangeData& data, 137 const gfx::Point& root_view_location, 138 int drag_operation) { 139 if (!target_view_) 140 return ui::DragDropTypes::DRAG_NONE; 141 142 gfx::Point target_view_location(root_view_location); 143 View::ConvertPointToTarget(root_view_, target_view_, &target_view_location); 144 ui::DropTargetEvent enter_event(data, 145 target_view_location, 146 target_view_location, 147 drag_operation); 148 return target_view_->OnDragUpdated(enter_event); 149 } 150 151 void DropHelper::NotifyDragExit() { 152 if (target_view_) 153 target_view_->OnDragExited(); 154 } 155 156 } // namespace views 157