| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/controls/textfield/textfield.h" | 5 #include "ui/views/controls/textfield/textfield.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 #include "ui/base/dragdrop/drag_drop_types.h" | 24 #include "ui/base/dragdrop/drag_drop_types.h" |
| 25 #include "ui/base/ime/text_input_client.h" | 25 #include "ui/base/ime/text_input_client.h" |
| 26 #include "ui/base/l10n/l10n_util.h" | 26 #include "ui/base/l10n/l10n_util.h" |
| 27 #include "ui/base/ui_base_switches.h" | 27 #include "ui/base/ui_base_switches.h" |
| 28 #include "ui/base/ui_base_switches_util.h" | 28 #include "ui/base/ui_base_switches_util.h" |
| 29 #include "ui/events/event.h" | 29 #include "ui/events/event.h" |
| 30 #include "ui/events/keycodes/keyboard_codes.h" | 30 #include "ui/events/keycodes/keyboard_codes.h" |
| 31 #include "ui/gfx/render_text.h" | 31 #include "ui/gfx/render_text.h" |
| 32 #include "ui/views/controls/textfield/textfield_controller.h" | 32 #include "ui/views/controls/textfield/textfield_controller.h" |
| 33 #include "ui/views/controls/textfield/textfield_model.h" | 33 #include "ui/views/controls/textfield/textfield_model.h" |
| 34 #include "ui/views/controls/textfield/textfield_test_api.h" |
| 34 #include "ui/views/focus/focus_manager.h" | 35 #include "ui/views/focus/focus_manager.h" |
| 35 #include "ui/views/ime/mock_input_method.h" | 36 #include "ui/views/ime/mock_input_method.h" |
| 36 #include "ui/views/test/test_views_delegate.h" | 37 #include "ui/views/test/test_views_delegate.h" |
| 37 #include "ui/views/test/views_test_base.h" | 38 #include "ui/views/test/views_test_base.h" |
| 38 #include "ui/views/widget/native_widget_private.h" | 39 #include "ui/views/widget/native_widget_private.h" |
| 39 #include "ui/views/widget/widget.h" | 40 #include "ui/views/widget/widget.h" |
| 40 #include "url/gurl.h" | 41 #include "url/gurl.h" |
| 41 | 42 |
| 42 #if defined(OS_WIN) | 43 #if defined(OS_WIN) |
| 43 #include "base/win/windows_version.h" | 44 #include "base/win/windows_version.h" |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 textfield_->set_controller(this); | 191 textfield_->set_controller(this); |
| 191 widget_ = new Widget(); | 192 widget_ = new Widget(); |
| 192 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); | 193 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
| 193 params.bounds = gfx::Rect(100, 100, 100, 100); | 194 params.bounds = gfx::Rect(100, 100, 100, 100); |
| 194 widget_->Init(params); | 195 widget_->Init(params); |
| 195 View* container = new View(); | 196 View* container = new View(); |
| 196 widget_->SetContentsView(container); | 197 widget_->SetContentsView(container); |
| 197 container->AddChildView(textfield_); | 198 container->AddChildView(textfield_); |
| 198 textfield_->SetBoundsRect(params.bounds); | 199 textfield_->SetBoundsRect(params.bounds); |
| 199 textfield_->set_id(1); | 200 textfield_->set_id(1); |
| 201 test_api_.reset(new TextfieldTestApi(textfield_)); |
| 200 | 202 |
| 201 for (int i = 1; i < count; i++) { | 203 for (int i = 1; i < count; i++) { |
| 202 Textfield* textfield = new Textfield(); | 204 Textfield* textfield = new Textfield(); |
| 203 container->AddChildView(textfield); | 205 container->AddChildView(textfield); |
| 204 textfield->set_id(i + 1); | 206 textfield->set_id(i + 1); |
| 205 } | 207 } |
| 206 | 208 |
| 207 model_ = textfield_->model_.get(); | 209 model_ = test_api_->model(); |
| 208 model_->ClearEditHistory(); | 210 model_->ClearEditHistory(); |
| 209 | 211 |
| 210 input_method_ = new MockInputMethod(); | 212 input_method_ = new MockInputMethod(); |
| 211 widget_->ReplaceInputMethod(input_method_); | 213 widget_->ReplaceInputMethod(input_method_); |
| 212 | 214 |
| 213 // Activate the widget and focus the textfield for input handling. | 215 // Activate the widget and focus the textfield for input handling. |
| 214 widget_->Activate(); | 216 widget_->Activate(); |
| 215 textfield_->RequestFocus(); | 217 textfield_->RequestFocus(); |
| 216 } | 218 } |
| 217 | 219 |
| 218 ui::MenuModel* GetContextMenuModel() { | 220 ui::MenuModel* GetContextMenuModel() { |
| 219 textfield_->UpdateContextMenu(); | 221 test_api_->UpdateContextMenu(); |
| 220 return textfield_->context_menu_contents_.get(); | 222 return test_api_->context_menu_contents(); |
| 221 } | |
| 222 | |
| 223 ui::TouchSelectionController* GetTouchSelectionController() { | |
| 224 return textfield_->touch_selection_controller_.get(); | |
| 225 } | 223 } |
| 226 | 224 |
| 227 protected: | 225 protected: |
| 228 void SendKeyEvent(ui::KeyboardCode key_code, | 226 void SendKeyEvent(ui::KeyboardCode key_code, |
| 229 bool alt, | 227 bool alt, |
| 230 bool shift, | 228 bool shift, |
| 231 bool control, | 229 bool control, |
| 232 bool caps_lock) { | 230 bool caps_lock) { |
| 233 int flags = (alt ? ui::EF_ALT_DOWN : 0) | | 231 int flags = (alt ? ui::EF_ALT_DOWN : 0) | |
| 234 (shift ? ui::EF_SHIFT_DOWN : 0) | | 232 (shift ? ui::EF_SHIFT_DOWN : 0) | |
| (...skipping 22 matching lines...) Expand all Loading... |
| 257 event.set_character(ch); | 255 event.set_character(ch); |
| 258 input_method_->DispatchKeyEvent(event); | 256 input_method_->DispatchKeyEvent(event); |
| 259 } | 257 } |
| 260 } | 258 } |
| 261 | 259 |
| 262 View* GetFocusedView() { | 260 View* GetFocusedView() { |
| 263 return widget_->GetFocusManager()->GetFocusedView(); | 261 return widget_->GetFocusManager()->GetFocusedView(); |
| 264 } | 262 } |
| 265 | 263 |
| 266 int GetCursorPositionX(int cursor_pos) { | 264 int GetCursorPositionX(int cursor_pos) { |
| 267 return textfield_->GetRenderText()->GetCursorBounds( | 265 return test_api_->GetRenderText()->GetCursorBounds( |
| 268 gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD), false).x(); | 266 gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD), false).x(); |
| 269 } | 267 } |
| 270 | 268 |
| 271 // Get the current cursor bounds. | 269 // Get the current cursor bounds. |
| 272 gfx::Rect GetCursorBounds() { | 270 gfx::Rect GetCursorBounds() { |
| 273 return textfield_->GetRenderText()->GetUpdatedCursorBounds(); | 271 return test_api_->GetRenderText()->GetUpdatedCursorBounds(); |
| 274 } | 272 } |
| 275 | 273 |
| 276 // Get the cursor bounds of |sel|. | 274 // Get the cursor bounds of |sel|. |
| 277 gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel) { | 275 gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel) { |
| 278 return textfield_->GetRenderText()->GetCursorBounds(sel, true); | 276 return test_api_->GetRenderText()->GetCursorBounds(sel, true); |
| 279 } | 277 } |
| 280 | 278 |
| 281 gfx::Rect GetDisplayRect() { | 279 gfx::Rect GetDisplayRect() { |
| 282 return textfield_->GetRenderText()->display_rect(); | 280 return test_api_->GetRenderText()->display_rect(); |
| 283 } | 281 } |
| 284 | 282 |
| 285 // Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and | 283 // Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and |
| 286 // y-axis is in the middle of |bound|'s vertical range. | 284 // y-axis is in the middle of |bound|'s vertical range. |
| 287 void MouseClick(const gfx::Rect bound, int x_offset) { | 285 void MouseClick(const gfx::Rect bound, int x_offset) { |
| 288 gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2); | 286 gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2); |
| 289 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point, | 287 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point, |
| 290 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); | 288 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 291 textfield_->OnMousePressed(click); | 289 textfield_->OnMousePressed(click); |
| 292 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point, | 290 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 317 menu->IsEnabledAt(4 /* PASTE */)); | 315 menu->IsEnabledAt(4 /* PASTE */)); |
| 318 EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(5 /* DELETE */)); | 316 EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(5 /* DELETE */)); |
| 319 EXPECT_TRUE(menu->IsEnabledAt(6 /* Separator */)); | 317 EXPECT_TRUE(menu->IsEnabledAt(6 /* Separator */)); |
| 320 EXPECT_TRUE(menu->IsEnabledAt(7 /* SELECT ALL */)); | 318 EXPECT_TRUE(menu->IsEnabledAt(7 /* SELECT ALL */)); |
| 321 } | 319 } |
| 322 | 320 |
| 323 // We need widget to populate wrapper class. | 321 // We need widget to populate wrapper class. |
| 324 Widget* widget_; | 322 Widget* widget_; |
| 325 | 323 |
| 326 TestTextfield* textfield_; | 324 TestTextfield* textfield_; |
| 325 scoped_ptr<TextfieldTestApi> test_api_; |
| 327 TextfieldModel* model_; | 326 TextfieldModel* model_; |
| 328 | 327 |
| 329 // The string from Controller::ContentsChanged callback. | 328 // The string from Controller::ContentsChanged callback. |
| 330 base::string16 last_contents_; | 329 base::string16 last_contents_; |
| 331 | 330 |
| 332 // For testing input method related behaviors. | 331 // For testing input method related behaviors. |
| 333 MockInputMethod* input_method_; | 332 MockInputMethod* input_method_; |
| 334 | 333 |
| 335 // Indicates how many times OnBeforeUserAction() is called. | 334 // Indicates how many times OnBeforeUserAction() is called. |
| 336 int on_before_user_action_; | 335 int on_before_user_action_; |
| (...skipping 1559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1896 EXPECT_STR_EQ("other", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); | 1895 EXPECT_STR_EQ("other", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| 1897 EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard()); | 1896 EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard()); |
| 1898 } | 1897 } |
| 1899 #endif | 1898 #endif |
| 1900 | 1899 |
| 1901 // Touch selection and dragging currently only works for chromeos. | 1900 // Touch selection and dragging currently only works for chromeos. |
| 1902 #if defined(OS_CHROMEOS) | 1901 #if defined(OS_CHROMEOS) |
| 1903 TEST_F(TextfieldTest, TouchSelectionAndDraggingTest) { | 1902 TEST_F(TextfieldTest, TouchSelectionAndDraggingTest) { |
| 1904 InitTextfield(); | 1903 InitTextfield(); |
| 1905 textfield_->SetText(ASCIIToUTF16("hello world")); | 1904 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 1906 EXPECT_FALSE(GetTouchSelectionController()); | 1905 EXPECT_FALSE(test_api_->touch_selection_controller()); |
| 1907 const int x = GetCursorPositionX(2); | 1906 const int x = GetCursorPositionX(2); |
| 1908 GestureEventForTest tap(ui::ET_GESTURE_TAP, x, 0, 1.0f, 0.0f); | 1907 GestureEventForTest tap(ui::ET_GESTURE_TAP, x, 0, 1.0f, 0.0f); |
| 1909 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, x, 0, 0.0f, 0.0f); | 1908 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, x, 0, 0.0f, 0.0f); |
| 1910 GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, x, 0, 0.0f, 0.0f); | 1909 GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, x, 0, 0.0f, 0.0f); |
| 1911 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing); | 1910 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing); |
| 1912 | 1911 |
| 1913 // Tapping on the textfield should turn on the TouchSelectionController. | 1912 // Tapping on the textfield should turn on the TouchSelectionController. |
| 1914 textfield_->OnGestureEvent(&tap); | 1913 textfield_->OnGestureEvent(&tap); |
| 1915 EXPECT_TRUE(GetTouchSelectionController()); | 1914 EXPECT_TRUE(test_api_->touch_selection_controller()); |
| 1916 | 1915 |
| 1917 // Un-focusing the textfield should reset the TouchSelectionController | 1916 // Un-focusing the textfield should reset the TouchSelectionController |
| 1918 textfield_->GetFocusManager()->ClearFocus(); | 1917 textfield_->GetFocusManager()->ClearFocus(); |
| 1919 EXPECT_FALSE(GetTouchSelectionController()); | 1918 EXPECT_FALSE(test_api_->touch_selection_controller()); |
| 1920 | 1919 |
| 1921 // With touch editing enabled, long press should not show context menu. | 1920 // With touch editing enabled, long press should not show context menu. |
| 1922 // Instead, select word and invoke TouchSelectionController. | 1921 // Instead, select word and invoke TouchSelectionController. |
| 1923 textfield_->OnGestureEvent(&tap_down); | 1922 textfield_->OnGestureEvent(&tap_down); |
| 1924 textfield_->OnGestureEvent(&long_press); | 1923 textfield_->OnGestureEvent(&long_press); |
| 1925 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); | 1924 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| 1926 EXPECT_TRUE(GetTouchSelectionController()); | 1925 EXPECT_TRUE(test_api_->touch_selection_controller()); |
| 1927 | 1926 |
| 1928 // With touch drag drop enabled, long pressing in the selected region should | 1927 // With touch drag drop enabled, long pressing in the selected region should |
| 1929 // start a drag and remove TouchSelectionController. | 1928 // start a drag and remove TouchSelectionController. |
| 1930 ASSERT_TRUE(switches::IsTouchDragDropEnabled()); | 1929 ASSERT_TRUE(switches::IsTouchDragDropEnabled()); |
| 1931 textfield_->OnGestureEvent(&tap_down); | 1930 textfield_->OnGestureEvent(&tap_down); |
| 1932 textfield_->OnGestureEvent(&long_press); | 1931 textfield_->OnGestureEvent(&long_press); |
| 1933 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); | 1932 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| 1934 EXPECT_FALSE(GetTouchSelectionController()); | 1933 EXPECT_FALSE(test_api_->touch_selection_controller()); |
| 1935 | 1934 |
| 1936 // After disabling touch drag drop, long pressing again in the selection | 1935 // After disabling touch drag drop, long pressing again in the selection |
| 1937 // region should not do anything. | 1936 // region should not do anything. |
| 1938 CommandLine::ForCurrentProcess()->AppendSwitch( | 1937 CommandLine::ForCurrentProcess()->AppendSwitch( |
| 1939 switches::kDisableTouchDragDrop); | 1938 switches::kDisableTouchDragDrop); |
| 1940 ASSERT_FALSE(switches::IsTouchDragDropEnabled()); | 1939 ASSERT_FALSE(switches::IsTouchDragDropEnabled()); |
| 1941 textfield_->OnGestureEvent(&tap_down); | 1940 textfield_->OnGestureEvent(&tap_down); |
| 1942 textfield_->OnGestureEvent(&long_press); | 1941 textfield_->OnGestureEvent(&long_press); |
| 1943 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); | 1942 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| 1944 EXPECT_TRUE(GetTouchSelectionController()); | 1943 EXPECT_TRUE(test_api_->touch_selection_controller()); |
| 1945 EXPECT_TRUE(long_press.handled()); | 1944 EXPECT_TRUE(long_press.handled()); |
| 1946 } | 1945 } |
| 1947 | 1946 |
| 1948 TEST_F(TextfieldTest, TouchScrubbingSelection) { | 1947 TEST_F(TextfieldTest, TouchScrubbingSelection) { |
| 1949 InitTextfield(); | 1948 InitTextfield(); |
| 1950 textfield_->SetText(ASCIIToUTF16("hello world")); | 1949 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 1951 EXPECT_FALSE(GetTouchSelectionController()); | 1950 EXPECT_FALSE(test_api_->touch_selection_controller()); |
| 1952 | 1951 |
| 1953 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing); | 1952 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing); |
| 1954 | 1953 |
| 1955 // Simulate touch-scrubbing. | 1954 // Simulate touch-scrubbing. |
| 1956 int scrubbing_start = GetCursorPositionX(1); | 1955 int scrubbing_start = GetCursorPositionX(1); |
| 1957 int scrubbing_end = GetCursorPositionX(6); | 1956 int scrubbing_end = GetCursorPositionX(6); |
| 1958 | 1957 |
| 1959 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, scrubbing_start, 0, | 1958 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, scrubbing_start, 0, |
| 1960 0.0f, 0.0f); | 1959 0.0f, 0.0f); |
| 1961 textfield_->OnGestureEvent(&tap_down); | 1960 textfield_->OnGestureEvent(&tap_down); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1975 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, scrubbing_end, 0, | 1974 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, scrubbing_end, 0, |
| 1976 0.0f, 0.0f); | 1975 0.0f, 0.0f); |
| 1977 textfield_->OnGestureEvent(&scroll_end); | 1976 textfield_->OnGestureEvent(&scroll_end); |
| 1978 | 1977 |
| 1979 GestureEventForTest end(ui::ET_GESTURE_END, scrubbing_end, 0, 0.0f, 0.0f); | 1978 GestureEventForTest end(ui::ET_GESTURE_END, scrubbing_end, 0, 0.0f, 0.0f); |
| 1980 textfield_->OnGestureEvent(&end); | 1979 textfield_->OnGestureEvent(&end); |
| 1981 | 1980 |
| 1982 // In the end, part of text should have been selected and handles should have | 1981 // In the end, part of text should have been selected and handles should have |
| 1983 // appeared. | 1982 // appeared. |
| 1984 EXPECT_STR_EQ("ello ", textfield_->GetSelectedText()); | 1983 EXPECT_STR_EQ("ello ", textfield_->GetSelectedText()); |
| 1985 EXPECT_TRUE(GetTouchSelectionController()); | 1984 EXPECT_TRUE(test_api_->touch_selection_controller()); |
| 1986 } | 1985 } |
| 1987 #endif | 1986 #endif |
| 1988 | 1987 |
| 1989 // Long_Press gesture in Textfield can initiate a drag and drop now. | 1988 // Long_Press gesture in Textfield can initiate a drag and drop now. |
| 1990 TEST_F(TextfieldTest, TestLongPressInitiatesDragDrop) { | 1989 TEST_F(TextfieldTest, TestLongPressInitiatesDragDrop) { |
| 1991 InitTextfield(); | 1990 InitTextfield(); |
| 1992 textfield_->SetText(ASCIIToUTF16("Hello string world")); | 1991 textfield_->SetText(ASCIIToUTF16("Hello string world")); |
| 1993 | 1992 |
| 1994 // Ensure the textfield will provide selected text for drag data. | 1993 // Ensure the textfield will provide selected text for drag data. |
| 1995 textfield_->SelectRange(gfx::Range(6, 12)); | 1994 textfield_->SelectRange(gfx::Range(6, 12)); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2015 // Set text which may fall back to a font which has taller baseline than | 2014 // Set text which may fall back to a font which has taller baseline than |
| 2016 // the default font. | 2015 // the default font. |
| 2017 textfield_->SetText(UTF8ToUTF16("\xE0\xB9\x91")); | 2016 textfield_->SetText(UTF8ToUTF16("\xE0\xB9\x91")); |
| 2018 const int new_baseline = textfield_->GetBaseline(); | 2017 const int new_baseline = textfield_->GetBaseline(); |
| 2019 | 2018 |
| 2020 // Regardless of the text, the baseline must be the same. | 2019 // Regardless of the text, the baseline must be the same. |
| 2021 EXPECT_EQ(new_baseline, old_baseline); | 2020 EXPECT_EQ(new_baseline, old_baseline); |
| 2022 } | 2021 } |
| 2023 | 2022 |
| 2024 } // namespace views | 2023 } // namespace views |
| OLD | NEW |