summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--views/controls/textfield/native_textfield_views.cc112
-rw-r--r--views/controls/textfield/native_textfield_views.h22
-rw-r--r--views/controls/textfield/native_textfield_views_unittest.cc247
-rw-r--r--views/events/event.h1
-rw-r--r--views/widget/drop_helper.cc5
5 files changed, 380 insertions, 7 deletions
diff --git a/views/controls/textfield/native_textfield_views.cc b/views/controls/textfield/native_textfield_views.cc
index 3170878..5b8e556 100644
--- a/views/controls/textfield/native_textfield_views.cc
+++ b/views/controls/textfield/native_textfield_views.cc
@@ -12,6 +12,7 @@
#include "base/utf_string_conversions.h"
#include "grit/app_strings.h"
#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/range/range.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/canvas_skia.h"
@@ -66,6 +67,7 @@ NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
insert_(true),
is_cursor_visible_(false),
skip_input_method_cancel_composition_(false),
+ initiating_drag_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)),
aggregated_clicks_(0),
last_click_time_(base::Time::FromInternalValue(0)),
@@ -78,6 +80,7 @@ NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE);
SetContextMenuController(this);
+ SetDragController(this);
}
NativeTextfieldViews::~NativeTextfieldViews() {
@@ -102,9 +105,13 @@ bool NativeTextfieldViews::OnMousePressed(const MouseEvent& event) {
last_click_time_ = event.time_stamp();
last_click_location_ = event.location();
+ initiating_drag_ = false;
switch(aggregated_clicks_) {
case 0:
- MoveCursorTo(event.location(), event.IsShiftDown());
+ if (!IsPointInSelection(event.location()))
+ MoveCursorTo(event.location(), event.IsShiftDown());
+ else
+ initiating_drag_ = true;
break;
case 1:
model_->SelectWord();
@@ -123,6 +130,10 @@ bool NativeTextfieldViews::OnMousePressed(const MouseEvent& event) {
}
bool NativeTextfieldViews::OnMouseDragged(const MouseEvent& event) {
+ // Don't adjust the cursor on a potential drag and drop.
+ if (initiating_drag_)
+ return true;
+
OnBeforeUserAction();
if (MoveCursorTo(event.location(), true))
SchedulePaint();
@@ -130,6 +141,15 @@ bool NativeTextfieldViews::OnMouseDragged(const MouseEvent& event) {
return true;
}
+void NativeTextfieldViews::OnMouseReleased(const MouseEvent& event) {
+ OnBeforeUserAction();
+ // Cancel suspected drag initiations, the user was clicking in the selection.
+ if (initiating_drag_ && MoveCursorTo(event.location(), false))
+ SchedulePaint();
+ initiating_drag_ = false;
+ OnAfterUserAction();
+}
+
bool NativeTextfieldViews::OnKeyPressed(const KeyEvent& event) {
// OnKeyPressed/OnKeyReleased/OnFocus/OnBlur will never be invoked on
// NativeTextfieldViews as it will never gain focus.
@@ -142,6 +162,64 @@ bool NativeTextfieldViews::OnKeyReleased(const KeyEvent& event) {
return false;
}
+bool NativeTextfieldViews::GetDropFormats(
+ int* formats,
+ std::set<OSExchangeData::CustomFormat>* custom_formats) {
+ if (!textfield_->IsEnabled() || textfield_->read_only())
+ return false;
+ // TODO(msw): Can we support URL, FILENAME, etc.?
+ *formats = ui::OSExchangeData::STRING;
+ return true;
+}
+
+bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) {
+ return textfield_->IsEnabled() && !textfield_->read_only() &&
+ data.HasString();
+}
+
+int NativeTextfieldViews::OnDragUpdated(const DropTargetEvent& event) {
+ // TODO(msw): retain unfocused selection, render secondary cursor...
+ DCHECK(CanDrop(event.data()));
+ if (initiating_drag_) {
+ if (IsPointInSelection(event.location()))
+ return ui::DragDropTypes::DRAG_NONE;
+ return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
+ ui::DragDropTypes::DRAG_MOVE;
+ }
+ return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
+}
+
+int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) {
+ DCHECK(CanDrop(event.data()));
+ DCHECK(!initiating_drag_ || !IsPointInSelection(event.location()));
+ OnBeforeUserAction();
+ size_t drop_destination = FindCursorPosition(event.location());
+ // We'll delete the current selection for a drag and drop within this view.
+ bool move = initiating_drag_ && !event.IsControlDown() &&
+ event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
+ if (move) {
+ ui::Range selected_range;
+ model_->GetSelectedRange(&selected_range);
+ // Adjust the drop destination if it is on or after the current selection.
+ if (selected_range.GetMax() <= drop_destination)
+ drop_destination -= selected_range.length();
+ else if (selected_range.GetMin() <= drop_destination)
+ drop_destination = selected_range.GetMin();
+ model_->DeleteSelection();
+ }
+ model_->MoveCursorTo(drop_destination, false);
+ string16 text;
+ event.data().GetString(&text);
+ InsertText(text);
+ UpdateCursorBoundsAndTextOffset();
+ OnAfterUserAction();
+ return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
+}
+
+void NativeTextfieldViews::OnDragDone() {
+ initiating_drag_ = false;
+}
+
void NativeTextfieldViews::OnPaint(gfx::Canvas* canvas) {
text_border_->set_has_focus(textfield_->HasFocus());
OnPaintBackground(canvas);
@@ -159,11 +237,14 @@ void NativeTextfieldViews::OnBlur() {
}
gfx::NativeCursor NativeTextfieldViews::GetCursor(const MouseEvent& event) {
+ bool text = !initiating_drag_ && (event.type() == ui::ET_MOUSE_DRAGGED ||
+ !IsPointInSelection(event.location()));
#if defined(OS_WIN)
static HCURSOR ibeam = LoadCursor(NULL, IDC_IBEAM);
- return ibeam;
+ static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW);
+ return text ? ibeam : arrow;
#else
- return gfx::GetCursor(GDK_XTERM);
+ return text ? gfx::GetCursor(GDK_XTERM) : NULL;
#endif
}
@@ -177,6 +258,31 @@ void NativeTextfieldViews::ShowContextMenuForView(View* source,
}
/////////////////////////////////////////////////////////////////
+// NativeTextfieldViews, views::DragController overrides:
+void NativeTextfieldViews::WriteDragDataForView(views::View* sender,
+ const gfx::Point& press_pt,
+ OSExchangeData* data) {
+ DCHECK_NE(ui::DragDropTypes::DRAG_NONE,
+ GetDragOperationsForView(sender, press_pt));
+ data->SetString(GetSelectedText());
+}
+
+int NativeTextfieldViews::GetDragOperationsForView(views::View* sender,
+ const gfx::Point& p) {
+ if (!textfield_->IsEnabled() || !IsPointInSelection(p))
+ return ui::DragDropTypes::DRAG_NONE;
+ if (sender == this && !textfield_->read_only())
+ return ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY;
+ return ui::DragDropTypes::DRAG_COPY;
+}
+
+bool NativeTextfieldViews::CanStartDragForView(View* sender,
+ const gfx::Point& press_pt,
+ const gfx::Point& p) {
+ return IsPointInSelection(press_pt);
+}
+
+/////////////////////////////////////////////////////////////////
// NativeTextfieldViews, NativeTextifieldWrapper overrides:
string16 NativeTextfieldViews::GetText() const {
diff --git a/views/controls/textfield/native_textfield_views.h b/views/controls/textfield/native_textfield_views.h
index 36b12c7..b20fcf1 100644
--- a/views/controls/textfield/native_textfield_views.h
+++ b/views/controls/textfield/native_textfield_views.h
@@ -41,6 +41,7 @@ class Menu2;
// * Undo/Redo
class NativeTextfieldViews : public View,
public ContextMenuController,
+ public DragController,
public NativeTextfieldWrapper,
public ui::SimpleMenuModel::Delegate,
public TextInputClient,
@@ -53,7 +54,15 @@ class NativeTextfieldViews : public View,
virtual gfx::NativeCursor GetCursor(const MouseEvent& event) OVERRIDE;
virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE;
virtual bool OnMouseDragged(const MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const MouseEvent& event) OVERRIDE;
virtual bool OnKeyPressed(const KeyEvent& event) OVERRIDE;
+ virtual bool GetDropFormats(
+ int* formats,
+ std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
+ virtual bool CanDrop(const OSExchangeData& data) OVERRIDE;
+ virtual int OnDragUpdated(const DropTargetEvent& event) OVERRIDE;
+ virtual int OnPerformDrop(const DropTargetEvent& event) OVERRIDE;
+ virtual void OnDragDone() OVERRIDE;
virtual bool OnKeyReleased(const KeyEvent& event) OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void OnFocus() OVERRIDE;
@@ -64,6 +73,16 @@ class NativeTextfieldViews : public View,
const gfx::Point& p,
bool is_mouse_gesture) OVERRIDE;
+ // Overridden from DragController:
+ virtual void WriteDragDataForView(View* sender,
+ const gfx::Point& press_pt,
+ OSExchangeData* data) OVERRIDE;
+ virtual int GetDragOperationsForView(View* sender,
+ const gfx::Point& p) OVERRIDE;
+ virtual bool CanStartDragForView(View* sender,
+ const gfx::Point& press_pt,
+ const gfx::Point& p) OVERRIDE;
+
// NativeTextfieldWrapper overrides:
virtual string16 GetText() const OVERRIDE;
virtual void UpdateText() OVERRIDE;
@@ -230,6 +249,9 @@ class NativeTextfieldViews : public View,
// True if InputMethod::CancelComposition() should not be called.
bool skip_input_method_cancel_composition_;
+ // Is the user potentially dragging and dropping from this view?
+ bool initiating_drag_;
+
// A runnable method factory for callback to update the cursor.
ScopedRunnableMethodFactory<NativeTextfieldViews> cursor_timer_;
diff --git a/views/controls/textfield/native_textfield_views_unittest.cc b/views/controls/textfield/native_textfield_views_unittest.cc
index cb35e79..4eb80db 100644
--- a/views/controls/textfield/native_textfield_views_unittest.cc
+++ b/views/controls/textfield/native_textfield_views_unittest.cc
@@ -7,10 +7,13 @@
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/message_loop.h"
+#include "base/pickle.h"
#include "base/utf_string_conversions.h"
+#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "views/controls/menu/menu_2.h"
#include "views/controls/textfield/native_textfield_views.h"
@@ -213,6 +216,12 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
return widget_->GetFocusManager()->GetFocusedView();
}
+ int GetCursorPositionX(int cursor_pos) {
+ const string16 text = textfield_->text().substr(0, cursor_pos);
+ return textfield_view_->GetInsets().left() + textfield_view_->text_offset_ +
+ textfield_view_->GetFont().GetStringWidth(text);
+ }
+
// We need widget to populate wrapper class.
Widget* widget_;
@@ -542,22 +551,256 @@ TEST_F(NativeTextfieldViewsTest, DoubleAndTripleClickTest) {
InitTextfield(Textfield::STYLE_DEFAULT);
textfield_->SetText(ASCIIToUTF16("hello world"));
MouseEvent click(ui::ET_MOUSE_PRESSED, 0, 0, ui::EF_LEFT_BUTTON_DOWN);
+ MouseEvent release(ui::ET_MOUSE_RELEASED, 0, 0, ui::EF_LEFT_BUTTON_DOWN);
MouseEvent double_click(ui::ET_MOUSE_PRESSED, 0, 0,
ui::EF_LEFT_BUTTON_DOWN | ui::EF_IS_DOUBLE_CLICK);
// Test for double click.
textfield_view_->OnMousePressed(click);
- EXPECT_STR_EQ("", textfield_->GetSelectedText());
+ textfield_view_->OnMouseReleased(release);
+ EXPECT_TRUE(textfield_->GetSelectedText().empty());
textfield_view_->OnMousePressed(double_click);
+ textfield_view_->OnMouseReleased(release);
EXPECT_STR_EQ("hello", textfield_->GetSelectedText());
// Test for triple click.
textfield_view_->OnMousePressed(click);
+ textfield_view_->OnMouseReleased(release);
EXPECT_STR_EQ("hello world", textfield_->GetSelectedText());
// Another click should reset back to single click.
textfield_view_->OnMousePressed(click);
- EXPECT_STR_EQ("", textfield_->GetSelectedText());
+ textfield_view_->OnMouseReleased(release);
+ EXPECT_TRUE(textfield_->GetSelectedText().empty());
+}
+
+TEST_F(NativeTextfieldViewsTest, DragToSelect) {
+ InitTextfield(Textfield::STYLE_DEFAULT);
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+ const int kStart = GetCursorPositionX(5);
+ const int kEnd = 500;
+ MouseEvent click_a(ui::ET_MOUSE_PRESSED, kStart, 0, ui::EF_LEFT_BUTTON_DOWN);
+ MouseEvent click_b(ui::ET_MOUSE_PRESSED, kEnd, 0, ui::EF_LEFT_BUTTON_DOWN);
+ MouseEvent drag_left(ui::ET_MOUSE_DRAGGED, 0, 0, ui::EF_LEFT_BUTTON_DOWN);
+ MouseEvent drag_right(ui::ET_MOUSE_DRAGGED, kEnd, 0, ui::EF_LEFT_BUTTON_DOWN);
+ MouseEvent release(ui::ET_MOUSE_RELEASED, kEnd, 0, ui::EF_LEFT_BUTTON_DOWN);
+ textfield_view_->OnMousePressed(click_a);
+ EXPECT_TRUE(textfield_->GetSelectedText().empty());
+ // Check that dragging left selects the beginning of the string.
+ textfield_view_->OnMouseDragged(drag_left);
+ string16 text_left = textfield_->GetSelectedText();
+ EXPECT_STR_EQ("hello", text_left);
+ // Check that dragging right selects the rest of the string.
+ textfield_view_->OnMouseDragged(drag_right);
+ string16 text_right = textfield_->GetSelectedText();
+ EXPECT_STR_EQ(" world", text_right);
+ // Check that releasing in the same location does not alter the selection.
+ textfield_view_->OnMouseReleased(release);
+ EXPECT_EQ(text_right, textfield_->GetSelectedText());
+ // Check that dragging from beyond the text length works too.
+ textfield_view_->OnMousePressed(click_b);
+ textfield_view_->OnMouseDragged(drag_left);
+ textfield_view_->OnMouseReleased(release);
+ EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText());
+}
+
+TEST_F(NativeTextfieldViewsTest, DragAndDrop_AcceptDrop) {
+ InitTextfield(Textfield::STYLE_DEFAULT);
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+
+ ui::OSExchangeData data;
+ string16 string(ASCIIToUTF16("string "));
+ data.SetString(string);
+ int formats = 0;
+ std::set<OSExchangeData::CustomFormat> custom_formats;
+
+ // Ensure that disabled textfields do not accept drops.
+ textfield_->SetEnabled(false);
+ EXPECT_FALSE(textfield_view_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_EQ(0, formats);
+ EXPECT_TRUE(custom_formats.empty());
+ EXPECT_FALSE(textfield_view_->CanDrop(data));
+ textfield_->SetEnabled(true);
+
+ // Ensure that read-only textfields do not accept drops.
+ textfield_->SetReadOnly(true);
+ EXPECT_FALSE(textfield_view_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_EQ(0, formats);
+ EXPECT_TRUE(custom_formats.empty());
+ EXPECT_FALSE(textfield_view_->CanDrop(data));
+ textfield_->SetReadOnly(false);
+
+ // Ensure that enabled and editable textfields do accept drops.
+ EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_EQ(ui::OSExchangeData::STRING, formats);
+ EXPECT_TRUE(custom_formats.empty());
+ EXPECT_TRUE(textfield_view_->CanDrop(data));
+ DropTargetEvent drop(data, GetCursorPositionX(6), 0,
+ ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE,
+ textfield_view_->OnDragUpdated(drop));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_view_->OnPerformDrop(drop));
+ EXPECT_STR_EQ("hello string world", textfield_->text());
+
+ // Ensure that textfields do not accept non-OSExchangeData::STRING types.
+ ui::OSExchangeData bad_data;
+ bad_data.SetFilename(FilePath(FILE_PATH_LITERAL("x")));
+#if defined(OS_WIN)
+ bad_data.SetPickledData(CF_BITMAP, Pickle());
+ bad_data.SetFileContents(FilePath(L"x"), "x");
+ bad_data.SetHtml(string16(ASCIIToUTF16("x")), GURL("x.org"));
+ ui::OSExchangeData::DownloadFileInfo download(FilePath(), NULL);
+ bad_data.SetDownloadFileInfo(download);
+#else
+ // Skip OSExchangeDataProviderWin::SetURL, which also sets CF_TEXT / STRING.
+ bad_data.SetURL(GURL("x.org"), string16(ASCIIToUTF16("x")));
+ bad_data.SetPickledData(GDK_SELECTION_PRIMARY, Pickle());
+#endif
+ EXPECT_FALSE(textfield_view_->CanDrop(bad_data));
+}
+
+TEST_F(NativeTextfieldViewsTest, DragAndDrop_InitiateDrag) {
+ InitTextfield(Textfield::STYLE_DEFAULT);
+ textfield_->SetText(ASCIIToUTF16("hello string world"));
+
+ // Ensure the textfield will provide selected text for drag data.
+ string16 string;
+ ui::OSExchangeData data;
+ const ui::Range kStringRange(6, 12);
+ textfield_->SelectRange(kStringRange);
+ const gfx::Point kStringPoint(GetCursorPositionX(9), 0);
+ textfield_view_->WriteDragDataForView(NULL, kStringPoint, &data);
+ EXPECT_TRUE(data.GetString(&string));
+ EXPECT_EQ(textfield_->GetSelectedText(), string);
+
+ // Ensure that disabled textfields do not support drag operations.
+ textfield_->SetEnabled(false);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
+ textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
+ textfield_->SetEnabled(true);
+ // Ensure that textfields without selections do not support drag operations.
+ textfield_->ClearSelection();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
+ textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
+ textfield_->SelectRange(kStringRange);
+ // Ensure that textfields only initiate drag operations inside the selection.
+ EXPECT_EQ(ui::DragDropTypes::DRAG_NONE,
+ textfield_view_->GetDragOperationsForView(NULL, gfx::Point()));
+ EXPECT_FALSE(textfield_view_->CanStartDragForView(NULL, gfx::Point(),
+ gfx::Point()));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY,
+ textfield_view_->GetDragOperationsForView(NULL, kStringPoint));
+ EXPECT_TRUE(textfield_view_->CanStartDragForView(NULL, kStringPoint,
+ gfx::Point()));
+ // Ensure that textfields support local moves.
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
+ textfield_view_->GetDragOperationsForView(textfield_view_, kStringPoint));
+}
+
+TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheRight) {
+ InitTextfield(Textfield::STYLE_DEFAULT);
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+
+ string16 string;
+ ui::OSExchangeData data;
+ int formats = 0;
+ int operations = 0;
+ std::set<OSExchangeData::CustomFormat> custom_formats;
+
+ // Start dragging "ello".
+ textfield_->SelectRange(ui::Range(1, 5));
+ MouseEvent click_a(ui::ET_MOUSE_PRESSED, GetCursorPositionX(3), 0,
+ ui::EF_LEFT_BUTTON_DOWN);
+ textfield_view_->OnMousePressed(click_a);
+ EXPECT_TRUE(textfield_view_->CanStartDragForView(textfield_view_,
+ click_a.location(), gfx::Point()));
+ operations = textfield_view_->GetDragOperationsForView(textfield_view_,
+ click_a.location());
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
+ operations);
+ textfield_view_->WriteDragDataForView(NULL, click_a.location(), &data);
+ EXPECT_TRUE(data.GetString(&string));
+ EXPECT_EQ(textfield_->GetSelectedText(), string);
+ EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_EQ(ui::OSExchangeData::STRING, formats);
+ EXPECT_TRUE(custom_formats.empty());
+
+ // Drop "ello" after "w".
+ const gfx::Point kDropPoint(GetCursorPositionX(7), 0);
+ EXPECT_TRUE(textfield_view_->CanDrop(data));
+ DropTargetEvent drop_a(data, kDropPoint.x(), 0, operations);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
+ textfield_view_->OnDragUpdated(drop_a));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
+ textfield_view_->OnPerformDrop(drop_a));
+ EXPECT_STR_EQ("h welloorld", textfield_->text());
+ textfield_view_->OnDragDone();
+}
+
+TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheLeft) {
+ InitTextfield(Textfield::STYLE_DEFAULT);
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+
+ string16 string;
+ ui::OSExchangeData data;
+ int formats = 0;
+ int operations = 0;
+ std::set<OSExchangeData::CustomFormat> custom_formats;
+
+ // Start dragging " worl".
+ textfield_->SelectRange(ui::Range(5, 10));
+ MouseEvent click_a(ui::ET_MOUSE_PRESSED, GetCursorPositionX(7), 0,
+ ui::EF_LEFT_BUTTON_DOWN);
+ textfield_view_->OnMousePressed(click_a);
+ EXPECT_TRUE(textfield_view_->CanStartDragForView(textfield_view_,
+ click_a.location(), gfx::Point()));
+ operations = textfield_view_->GetDragOperationsForView(textfield_view_,
+ click_a.location());
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY,
+ operations);
+ textfield_view_->WriteDragDataForView(NULL, click_a.location(), &data);
+ EXPECT_TRUE(data.GetString(&string));
+ EXPECT_EQ(textfield_->GetSelectedText(), string);
+ EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats));
+ EXPECT_EQ(ui::OSExchangeData::STRING, formats);
+ EXPECT_TRUE(custom_formats.empty());
+
+ // Drop " worl" after "h".
+ EXPECT_TRUE(textfield_view_->CanDrop(data));
+ DropTargetEvent drop_a(data, GetCursorPositionX(1), 0, operations);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
+ textfield_view_->OnDragUpdated(drop_a));
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE,
+ textfield_view_->OnPerformDrop(drop_a));
+ EXPECT_STR_EQ("h worlellod", textfield_->text());
+ textfield_view_->OnDragDone();
+}
+
+TEST_F(NativeTextfieldViewsTest, DragAndDrop_Canceled) {
+ InitTextfield(Textfield::STYLE_DEFAULT);
+ textfield_->SetText(ASCIIToUTF16("hello world"));
+
+ // Start dragging "worl".
+ textfield_->SelectRange(ui::Range(6, 10));
+ MouseEvent click(ui::ET_MOUSE_PRESSED, GetCursorPositionX(8), 0,
+ ui::EF_LEFT_BUTTON_DOWN);
+ textfield_view_->OnMousePressed(click);
+ ui::OSExchangeData data;
+ textfield_view_->WriteDragDataForView(NULL, click.location(), &data);
+ EXPECT_TRUE(textfield_view_->CanDrop(data));
+ // Drag the text over somewhere valid, outside the current selection.
+ DropTargetEvent drop(data, GetCursorPositionX(2), 0,
+ ui::DragDropTypes::DRAG_MOVE);
+ EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_view_->OnDragUpdated(drop));
+ // "Cancel" the drag, via move and release over the selection, and OnDragDone.
+ MouseEvent drag(ui::ET_MOUSE_DRAGGED, GetCursorPositionX(9), 0,
+ ui::EF_LEFT_BUTTON_DOWN);
+ MouseEvent release(ui::ET_MOUSE_RELEASED, GetCursorPositionX(9), 0,
+ ui::EF_LEFT_BUTTON_DOWN);
+ textfield_view_->OnMouseDragged(drag);
+ textfield_view_->OnMouseReleased(release);
+ textfield_view_->OnDragDone();
+ EXPECT_EQ(ASCIIToUTF16("hello world"), textfield_->text());
}
TEST_F(NativeTextfieldViewsTest, ReadOnlyTest) {
diff --git a/views/events/event.h b/views/events/event.h
index fbe3556..88b4693 100644
--- a/views/events/event.h
+++ b/views/events/event.h
@@ -382,6 +382,7 @@ class DropTargetEvent : public LocatedEvent {
: LocatedEvent(ui::ET_DROP_TARGET_EVENT, gfx::Point(x, y), 0),
data_(data),
source_operations_(source_operations) {
+ // TODO(msw): Hook up key state flags for CTRL + drag and drop, etc.
}
const OSExchangeData& data() const { return data_; }
diff --git a/views/widget/drop_helper.cc b/views/widget/drop_helper.cc
index 4090a6b..a0b7b76 100644
--- a/views/widget/drop_helper.cc
+++ b/views/widget/drop_helper.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -61,7 +61,8 @@ int DropHelper::OnDrop(const OSExchangeData& data,
}
gfx::Point view_location(root_view_location);
- View::ConvertPointToView(NULL, drop_view, &view_location);
+ View* root_view = drop_view->GetRootView();
+ View::ConvertPointToView(root_view, drop_view, &view_location);
DropTargetEvent drop_event(data, view_location.x(), view_location.y(),
drag_operation);
return drop_view->OnPerformDrop(drop_event);