summaryrefslogtreecommitdiffstats
path: root/chrome/views/root_view_drop_target.cc
blob: 8920234f71b7c8d749d433e9954ec70899ce372a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/views/root_view_drop_target.h"

#include "base/gfx/point.h"
#include "base/logging.h"
#include "chrome/common/drag_drop_types.h"
#include "chrome/views/root_view.h"
#include "chrome/views/widget.h"

namespace views {

RootViewDropTarget::RootViewDropTarget(RootView* root_view)
    : BaseDropTarget(root_view->GetWidget()->GetHWND()),
      root_view_(root_view),
      target_view_(NULL),
      deepest_view_(NULL) {
}

RootViewDropTarget::~RootViewDropTarget() {
}

void RootViewDropTarget::ResetTargetViewIfEquals(View* view) {
  if (target_view_ == view)
    target_view_ = NULL;
  if (deepest_view_ == view)
    deepest_view_ = NULL;
}

DWORD RootViewDropTarget::OnDragOver(IDataObject* data_object,
                                     DWORD key_state,
                                     POINT cursor_position,
                                     DWORD effect) {
  const OSExchangeData data(data_object);
  gfx::Point root_view_location(cursor_position.x, cursor_position.y);
  View::ConvertPointToView(NULL, root_view_, &root_view_location);
  View* view = CalculateTargetView(root_view_location, data);

  if (view != target_view_) {
    // Target changed notify old drag exited, then new drag entered.
    if (target_view_)
      target_view_->OnDragExited();
    target_view_ = view;
    if (target_view_) {
      gfx::Point target_view_location(root_view_location);
      View::ConvertPointToView(root_view_, target_view_, &target_view_location);
      DropTargetEvent enter_event(data,
          target_view_location.x(),
          target_view_location.y(),
          DragDropTypes::DropEffectToDragOperation(effect));
      target_view_->OnDragEntered(enter_event);
    }
  }

  if (target_view_) {
    gfx::Point target_view_location(root_view_location);
    View::ConvertPointToView(root_view_, target_view_, &target_view_location);
    DropTargetEvent enter_event(data,
        target_view_location.x(),
        target_view_location.y(),
        DragDropTypes::DropEffectToDragOperation(effect));
    int result_operation = target_view_->OnDragUpdated(enter_event);
    return DragDropTypes::DragOperationToDropEffect(result_operation);
  } else {
    return DROPEFFECT_NONE;
  }
}

void RootViewDropTarget::OnDragLeave(IDataObject* data_object) {
  if (target_view_)
    target_view_->OnDragExited();
  deepest_view_ = target_view_ = NULL;
}

DWORD RootViewDropTarget::OnDrop(IDataObject* data_object,
                                 DWORD key_state,
                                 POINT cursor_position,
                                 DWORD effect) {
  const OSExchangeData data(data_object);
  DWORD drop_effect = OnDragOver(data_object, key_state, cursor_position,
                                 effect);
  View* drop_view = target_view_;
  deepest_view_ = target_view_ = NULL;
  if (drop_effect != DROPEFFECT_NONE) {
    gfx::Point view_location(cursor_position.x, cursor_position.y);
    View::ConvertPointToView(NULL, drop_view, &view_location);
    DropTargetEvent drop_event(data, view_location.x(), view_location.y(),
        DragDropTypes::DropEffectToDragOperation(effect));
    return DragDropTypes::DragOperationToDropEffect(
        drop_view->OnPerformDrop(drop_event));
  } else {
    if (drop_view)
      drop_view->OnDragExited();
    return DROPEFFECT_NONE;
  }
}

View* RootViewDropTarget::CalculateTargetView(
    const gfx::Point& root_view_location,
    const OSExchangeData& data) {
  View* view = root_view_->GetViewForPoint(root_view_location);
  if (view == deepest_view_) {
    // The view the mouse is over hasn't changed; reuse the target.
    return target_view_;
  }
  // View under mouse changed, which means a new view may want the drop.
  // Walk the tree, stopping at target_view_ as we know it'll accept the
  // drop.
  deepest_view_ = view;
  while (view && view != target_view_ &&
         (!view->IsEnabled() || !view->CanDrop(data))) {
    view = view->GetParent();
  }
  return view;
}

}  // namespace views