Home | History | Annotate | Download | only in widget
      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 #elif !defined(OS_MACOSX)
    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