Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 10 #include "grit/ui_strings.h" | 10 #include "grit/ui_strings.h" |
| 11 #include "ui/base/accessibility/accessible_view_state.h" | 11 #include "ui/base/accessibility/accessible_view_state.h" |
| 12 #include "ui/base/clipboard/scoped_clipboard_writer.h" | |
| 12 #include "ui/base/dragdrop/drag_drop_types.h" | 13 #include "ui/base/dragdrop/drag_drop_types.h" |
| 13 #include "ui/base/dragdrop/drag_utils.h" | 14 #include "ui/base/dragdrop/drag_utils.h" |
| 14 #include "ui/base/resource/resource_bundle.h" | 15 #include "ui/base/resource/resource_bundle.h" |
| 15 #include "ui/base/ui_base_switches_util.h" | 16 #include "ui/base/ui_base_switches_util.h" |
| 16 #include "ui/events/event.h" | 17 #include "ui/events/event.h" |
| 17 #include "ui/events/keycodes/keyboard_codes.h" | 18 #include "ui/events/keycodes/keyboard_codes.h" |
| 18 #include "ui/gfx/canvas.h" | 19 #include "ui/gfx/canvas.h" |
| 19 #include "ui/gfx/insets.h" | 20 #include "ui/gfx/insets.h" |
| 20 #include "ui/native_theme/native_theme.h" | 21 #include "ui/native_theme/native_theme.h" |
| 21 #include "ui/views/background.h" | 22 #include "ui/views/background.h" |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 46 const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY; | 47 const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY; |
| 47 | 48 |
| 48 void ConvertRectToScreen(const views::View* src, gfx::Rect* r) { | 49 void ConvertRectToScreen(const views::View* src, gfx::Rect* r) { |
| 49 DCHECK(src); | 50 DCHECK(src); |
| 50 | 51 |
| 51 gfx::Point new_origin = r->origin(); | 52 gfx::Point new_origin = r->origin(); |
| 52 views::View::ConvertPointToScreen(src, &new_origin); | 53 views::View::ConvertPointToScreen(src, &new_origin); |
| 53 r->set_origin(new_origin); | 54 r->set_origin(new_origin); |
| 54 } | 55 } |
| 55 | 56 |
| 57 void UpdateSelectionClipboard(const base::string16& text) { | |
|
oshima
2014/01/22 21:40:55
do you need to pass text? Can't you just use GetSe
msw
2014/01/22 23:15:35
I changed this file-local to be a class function a
| |
| 58 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) | |
| 59 if (!text.empty()) | |
|
oshima
2014/01/22 21:40:55
nit: I believe you should have {} in this case.
msw
2014/01/22 23:15:35
Done.
| |
| 60 ui::ScopedClipboardWriter( | |
| 61 ui::Clipboard::GetForCurrentThread(), | |
| 62 ui::CLIPBOARD_TYPE_SELECTION).WriteText(text); | |
| 63 #endif | |
| 64 } | |
| 65 | |
| 56 } // namespace | 66 } // namespace |
| 57 | 67 |
| 58 namespace views { | 68 namespace views { |
| 59 | 69 |
| 60 // static | 70 // static |
| 61 const char Textfield::kViewClassName[] = "Textfield"; | 71 const char Textfield::kViewClassName[] = "Textfield"; |
| 62 | 72 |
| 63 // static | 73 // static |
| 64 size_t Textfield::GetCaretBlinkMs() { | 74 size_t Textfield::GetCaretBlinkMs() { |
| 65 static const size_t default_value = 500; | 75 static const size_t default_value = 500; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 144 OnCaretBoundsChanged(); | 154 OnCaretBoundsChanged(); |
| 145 SchedulePaint(); | 155 SchedulePaint(); |
| 146 } | 156 } |
| 147 | 157 |
| 148 base::i18n::TextDirection Textfield::GetTextDirection() const { | 158 base::i18n::TextDirection Textfield::GetTextDirection() const { |
| 149 return GetRenderText()->GetTextDirection(); | 159 return GetRenderText()->GetTextDirection(); |
| 150 } | 160 } |
| 151 | 161 |
| 152 void Textfield::SelectAll(bool reversed) { | 162 void Textfield::SelectAll(bool reversed) { |
| 153 model_->SelectAll(reversed); | 163 model_->SelectAll(reversed); |
| 154 OnCaretBoundsChanged(); | 164 UpdateSelectionClipboard(text()); |
| 155 SchedulePaint(); | 165 UpdateAfterChange(false, true); |
| 156 } | 166 } |
| 157 | 167 |
| 158 base::string16 Textfield::GetSelectedText() const { | 168 base::string16 Textfield::GetSelectedText() const { |
| 159 return model_->GetSelectedText(); | 169 return model_->GetSelectedText(); |
| 160 } | 170 } |
| 161 | 171 |
| 162 void Textfield::ClearSelection() { | 172 void Textfield::ClearSelection() { |
| 163 model_->ClearSelection(); | 173 model_->ClearSelection(); |
| 164 OnCaretBoundsChanged(); | 174 UpdateAfterChange(false, true); |
| 165 SchedulePaint(); | |
| 166 } | 175 } |
| 167 | 176 |
| 168 bool Textfield::HasSelection() const { | 177 bool Textfield::HasSelection() const { |
| 169 return !GetSelectedRange().is_empty(); | 178 return !GetSelectedRange().is_empty(); |
| 170 } | 179 } |
| 171 | 180 |
| 172 SkColor Textfield::GetTextColor() const { | 181 SkColor Textfield::GetTextColor() const { |
| 173 if (!use_default_text_color_) | 182 if (!use_default_text_color_) |
| 174 return text_color_; | 183 return text_color_; |
| 175 | 184 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 234 bool Textfield::IsIMEComposing() const { | 243 bool Textfield::IsIMEComposing() const { |
| 235 return model_->HasCompositionText(); | 244 return model_->HasCompositionText(); |
| 236 } | 245 } |
| 237 | 246 |
| 238 const gfx::Range& Textfield::GetSelectedRange() const { | 247 const gfx::Range& Textfield::GetSelectedRange() const { |
| 239 return GetRenderText()->selection(); | 248 return GetRenderText()->selection(); |
| 240 } | 249 } |
| 241 | 250 |
| 242 void Textfield::SelectRange(const gfx::Range& range) { | 251 void Textfield::SelectRange(const gfx::Range& range) { |
| 243 model_->SelectRange(range); | 252 model_->SelectRange(range); |
| 244 OnCaretBoundsChanged(); | 253 UpdateAfterChange(false, true); |
| 245 SchedulePaint(); | |
| 246 NotifyAccessibilityEvent( | |
| 247 ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true); | |
| 248 } | 254 } |
| 249 | 255 |
| 250 const gfx::SelectionModel& Textfield::GetSelectionModel() const { | 256 const gfx::SelectionModel& Textfield::GetSelectionModel() const { |
| 251 return GetRenderText()->selection_model(); | 257 return GetRenderText()->selection_model(); |
| 252 } | 258 } |
| 253 | 259 |
| 254 void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) { | 260 void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) { |
| 255 model_->SelectSelectionModel(sel); | 261 model_->SelectSelectionModel(sel); |
| 256 OnCaretBoundsChanged(); | 262 UpdateAfterChange(false, true); |
| 257 SchedulePaint(); | |
| 258 } | 263 } |
| 259 | 264 |
| 260 size_t Textfield::GetCursorPosition() const { | 265 size_t Textfield::GetCursorPosition() const { |
| 261 return model_->GetCursorPosition(); | 266 return model_->GetCursorPosition(); |
| 262 } | 267 } |
| 263 | 268 |
| 264 void Textfield::SetColor(SkColor value) { | 269 void Textfield::SetColor(SkColor value) { |
| 265 GetRenderText()->SetColor(value); | 270 GetRenderText()->SetColor(value); |
| 266 SchedulePaint(); | 271 SchedulePaint(); |
| 267 } | 272 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 else if (control && shift && !alt && editable) | 368 else if (control && shift && !alt && editable) |
| 364 cursor_changed = text_changed = model_->Redo(); | 369 cursor_changed = text_changed = model_->Redo(); |
| 365 break; | 370 break; |
| 366 case ui::VKEY_Y: | 371 case ui::VKEY_Y: |
| 367 if (control && !alt && editable) | 372 if (control && !alt && editable) |
| 368 cursor_changed = text_changed = model_->Redo(); | 373 cursor_changed = text_changed = model_->Redo(); |
| 369 break; | 374 break; |
| 370 case ui::VKEY_A: | 375 case ui::VKEY_A: |
| 371 if (control && !alt) { | 376 if (control && !alt) { |
| 372 model_->SelectAll(false); | 377 model_->SelectAll(false); |
| 378 UpdateSelectionClipboard(text()); | |
| 373 cursor_changed = true; | 379 cursor_changed = true; |
| 374 } | 380 } |
| 375 break; | 381 break; |
| 376 case ui::VKEY_X: | 382 case ui::VKEY_X: |
| 377 if (control && !alt && editable && readable) | 383 if (control && !alt && editable && readable) |
| 378 cursor_changed = text_changed = Cut(); | 384 cursor_changed = text_changed = Cut(); |
| 379 break; | 385 break; |
| 380 case ui::VKEY_C: | 386 case ui::VKEY_C: |
| 381 if (control && !alt && readable) | 387 if (control && !alt && readable) |
| 382 Copy(); | 388 Copy(); |
| 383 break; | 389 break; |
| 384 case ui::VKEY_V: | 390 case ui::VKEY_V: |
| 385 if (control && !alt && editable) | 391 if (control && !alt && editable) |
| 386 cursor_changed = text_changed = Paste(); | 392 cursor_changed = text_changed = Paste(); |
| 387 break; | 393 break; |
| 388 case ui::VKEY_RIGHT: | 394 case ui::VKEY_RIGHT: |
| 389 case ui::VKEY_LEFT: { | 395 case ui::VKEY_LEFT: { |
| 390 // We should ignore the alt-left/right keys because alt key doesn't make | 396 // We should ignore the alt-left/right keys because alt key doesn't make |
| 391 // any special effects for them and they can be shortcut keys such like | 397 // any special effects for them and they can be shortcut keys such like |
| 392 // forward/back of the browser history. | 398 // forward/back of the browser history. |
| 393 if (alt) | 399 if (alt) |
| 394 break; | 400 break; |
| 395 const gfx::Range selection_range = render_text->selection(); | 401 const gfx::Range selection_range = render_text->selection(); |
| 396 model_->MoveCursor( | 402 model_->MoveCursor( |
| 397 control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, | 403 control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, |
| 398 (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT, | 404 (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT, |
| 399 shift); | 405 shift); |
| 406 UpdateSelectionClipboard(GetSelectedText()); | |
| 400 cursor_changed = render_text->selection() != selection_range; | 407 cursor_changed = render_text->selection() != selection_range; |
| 401 break; | 408 break; |
| 402 } | 409 } |
| 403 case ui::VKEY_END: | 410 case ui::VKEY_END: |
| 404 case ui::VKEY_HOME: | 411 case ui::VKEY_HOME: |
| 405 if ((key_code == ui::VKEY_HOME) == | 412 if ((key_code == ui::VKEY_HOME) == |
| 406 (render_text->GetTextDirection() == base::i18n::RIGHT_TO_LEFT)) | 413 (render_text->GetTextDirection() == base::i18n::RIGHT_TO_LEFT)) |
| 407 model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, shift); | 414 model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, shift); |
| 408 else | 415 else |
| 409 model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, shift); | 416 model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, shift); |
| 417 UpdateSelectionClipboard(GetSelectedText()); | |
|
oshima
2014/01/22 21:40:55
Moving cursor clears the selection, so this should
msw
2014/01/22 23:15:35
If |shift| is true, MoveCursor may yield a selecte
| |
| 410 cursor_changed = true; | 418 cursor_changed = true; |
| 411 break; | 419 break; |
| 412 case ui::VKEY_BACK: | 420 case ui::VKEY_BACK: |
| 413 case ui::VKEY_DELETE: | 421 case ui::VKEY_DELETE: |
| 414 if (!editable) | 422 if (!editable) |
| 415 break; | 423 break; |
| 416 if (!model_->HasSelection()) { | 424 if (!model_->HasSelection()) { |
| 417 gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ? | 425 gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ? |
| 418 gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT; | 426 gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT; |
| 419 if (shift && control) { | 427 if (shift && control) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 453 // We must have input method in order to support text input. | 461 // We must have input method in order to support text input. |
| 454 DCHECK(GetInputMethod()); | 462 DCHECK(GetInputMethod()); |
| 455 UpdateAfterChange(text_changed, cursor_changed); | 463 UpdateAfterChange(text_changed, cursor_changed); |
| 456 OnAfterUserAction(); | 464 OnAfterUserAction(); |
| 457 return (text_changed || cursor_changed); | 465 return (text_changed || cursor_changed); |
| 458 } | 466 } |
| 459 return false; | 467 return false; |
| 460 } | 468 } |
| 461 | 469 |
| 462 bool Textfield::OnMousePressed(const ui::MouseEvent& event) { | 470 bool Textfield::OnMousePressed(const ui::MouseEvent& event) { |
| 463 OnBeforeUserAction(); | |
| 464 TrackMouseClicks(event); | 471 TrackMouseClicks(event); |
| 465 | 472 |
| 466 if (!controller_ || !controller_->HandleMouseEvent(this, event)) { | 473 if (!controller_ || !controller_->HandleMouseEvent(this, event)) { |
| 467 if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) | 474 if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) |
| 468 RequestFocus(); | 475 RequestFocus(); |
| 469 | 476 |
| 470 if (event.IsOnlyLeftMouseButton()) { | 477 if (event.IsOnlyLeftMouseButton()) { |
| 478 OnBeforeUserAction(); | |
| 471 initiating_drag_ = false; | 479 initiating_drag_ = false; |
| 472 bool can_drag = true; | |
| 473 | |
| 474 switch (aggregated_clicks_) { | 480 switch (aggregated_clicks_) { |
| 475 case 0: | 481 case 0: |
| 476 if (can_drag && | 482 if (GetRenderText()->IsPointInSelection(event.location())) |
| 477 GetRenderText()->IsPointInSelection(event.location())) { | |
| 478 initiating_drag_ = true; | 483 initiating_drag_ = true; |
| 479 } else { | 484 else |
| 480 MoveCursorTo(event.location(), event.IsShiftDown()); | 485 MoveCursorTo(event.location(), event.IsShiftDown()); |
| 481 } | |
| 482 break; | 486 break; |
| 483 case 1: | 487 case 1: |
| 484 MoveCursorTo(event.location(), false); | 488 model_->MoveCursorTo(event.location(), false); |
| 485 model_->SelectWord(); | 489 model_->SelectWord(); |
| 490 UpdateAfterChange(false, true); | |
| 486 double_click_word_ = GetRenderText()->selection(); | 491 double_click_word_ = GetRenderText()->selection(); |
| 487 OnCaretBoundsChanged(); | |
| 488 break; | 492 break; |
| 489 case 2: | 493 case 2: |
| 490 model_->SelectAll(false); | 494 SelectAll(false); |
| 491 OnCaretBoundsChanged(); | |
| 492 break; | 495 break; |
| 493 default: | 496 default: |
| 494 NOTREACHED(); | 497 NOTREACHED(); |
| 495 } | 498 } |
| 499 OnAfterUserAction(); | |
| 496 } | 500 } |
| 497 SchedulePaint(); | 501 |
| 502 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) | |
| 503 if (event.IsOnlyMiddleMouseButton()) { | |
| 504 if (GetRenderText()->IsPointInSelection(event.location())) { | |
| 505 OnBeforeUserAction(); | |
| 506 ClearSelection(); | |
| 507 ui::ScopedClipboardWriter( | |
| 508 ui::Clipboard::GetForCurrentThread(), | |
| 509 ui::CLIPBOARD_TYPE_SELECTION).WriteText(base::string16()); | |
|
oshima
2014/01/22 21:40:55
.. and you can just call UpdateSelectionClipboard(
msw
2014/01/22 23:15:35
No; here we specifically want to clear the selecti
| |
| 510 OnAfterUserAction(); | |
| 511 } else if(!read_only()) { | |
| 512 PasteSelectionClipboard(event); | |
| 513 } | |
| 514 } | |
| 515 #endif | |
| 498 } | 516 } |
| 499 | 517 |
| 500 OnAfterUserAction(); | |
| 501 touch_selection_controller_.reset(); | 518 touch_selection_controller_.reset(); |
| 502 return true; | 519 return true; |
| 503 } | 520 } |
| 504 | 521 |
| 505 bool Textfield::OnMouseDragged(const ui::MouseEvent& event) { | 522 bool Textfield::OnMouseDragged(const ui::MouseEvent& event) { |
| 506 // Don't adjust the cursor on a potential drag and drop, or if the mouse | 523 // Don't adjust the cursor on a potential drag and drop, or if the mouse |
| 507 // movement from the last mouse click does not exceed the drag threshold. | 524 // movement from the last mouse click does not exceed the drag threshold. |
| 508 if (initiating_drag_ || !event.IsOnlyLeftMouseButton() || | 525 if (initiating_drag_ || !event.IsOnlyLeftMouseButton() || |
| 509 !ExceededDragThreshold(event.location() - last_click_location_)) { | 526 !ExceededDragThreshold(event.location() - last_click_location_)) { |
| 510 return true; | 527 return true; |
| 511 } | 528 } |
| 512 | 529 |
| 513 if (!event.IsOnlyRightMouseButton()) { | 530 OnBeforeUserAction(); |
| 514 OnBeforeUserAction(); | 531 model_->MoveCursorTo(event.location(), true); |
| 515 MoveCursorTo(event.location(), true); | 532 if (aggregated_clicks_ == 1) { |
| 516 if (aggregated_clicks_ == 1) { | 533 model_->SelectWord(); |
| 517 model_->SelectWord(); | 534 // Expand the selection so the initially selected word remains selected. |
| 518 // Expand the selection so the initially selected word remains selected. | 535 gfx::Range selection = GetRenderText()->selection(); |
| 519 gfx::Range selection = GetRenderText()->selection(); | 536 const size_t min = std::min(selection.GetMin(), |
| 520 const size_t min = std::min(selection.GetMin(), | 537 double_click_word_.GetMin()); |
| 521 double_click_word_.GetMin()); | 538 const size_t max = std::max(selection.GetMax(), |
| 522 const size_t max = std::max(selection.GetMax(), | 539 double_click_word_.GetMax()); |
| 523 double_click_word_.GetMax()); | 540 const bool reversed = selection.is_reversed(); |
| 524 const bool reversed = selection.is_reversed(); | 541 selection.set_start(reversed ? max : min); |
| 525 selection.set_start(reversed ? max : min); | 542 selection.set_end(reversed ? min : max); |
| 526 selection.set_end(reversed ? min : max); | 543 model_->SelectRange(selection); |
| 527 model_->SelectRange(selection); | |
| 528 } | |
| 529 SchedulePaint(); | |
| 530 OnAfterUserAction(); | |
| 531 } | 544 } |
| 545 UpdateAfterChange(false, true); | |
| 546 OnAfterUserAction(); | |
| 532 return true; | 547 return true; |
| 533 } | 548 } |
| 534 | 549 |
| 535 void Textfield::OnMouseReleased(const ui::MouseEvent& event) { | 550 void Textfield::OnMouseReleased(const ui::MouseEvent& event) { |
| 536 OnBeforeUserAction(); | 551 OnBeforeUserAction(); |
| 537 // Cancel suspected drag initiations, the user was clicking in the selection. | 552 // Cancel suspected drag initiations, the user was clicking in the selection. |
| 538 if (initiating_drag_ && MoveCursorTo(event.location(), false)) | 553 if (initiating_drag_) |
| 539 SchedulePaint(); | 554 MoveCursorTo(event.location(), false); |
| 540 initiating_drag_ = false; | 555 initiating_drag_ = false; |
| 556 UpdateSelectionClipboard(GetSelectedText()); | |
| 541 OnAfterUserAction(); | 557 OnAfterUserAction(); |
| 542 } | 558 } |
| 543 | 559 |
| 544 void Textfield::OnFocus() { | 560 void Textfield::OnFocus() { |
| 545 GetRenderText()->set_focused(true); | 561 GetRenderText()->set_focused(true); |
| 546 cursor_visible_ = true; | 562 cursor_visible_ = true; |
| 547 SchedulePaint(); | 563 SchedulePaint(); |
| 548 GetInputMethod()->OnFocus(); | 564 GetInputMethod()->OnFocus(); |
| 549 OnCaretBoundsChanged(); | 565 OnCaretBoundsChanged(); |
| 550 | 566 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 630 #endif | 646 #endif |
| 631 } | 647 } |
| 632 | 648 |
| 633 void Textfield::OnGestureEvent(ui::GestureEvent* event) { | 649 void Textfield::OnGestureEvent(ui::GestureEvent* event) { |
| 634 switch (event->type()) { | 650 switch (event->type()) { |
| 635 case ui::ET_GESTURE_TAP_DOWN: | 651 case ui::ET_GESTURE_TAP_DOWN: |
| 636 OnBeforeUserAction(); | 652 OnBeforeUserAction(); |
| 637 RequestFocus(); | 653 RequestFocus(); |
| 638 // We don't deselect if the point is in the selection | 654 // We don't deselect if the point is in the selection |
| 639 // because TAP_DOWN may turn into a LONG_PRESS. | 655 // because TAP_DOWN may turn into a LONG_PRESS. |
| 640 if (!GetRenderText()->IsPointInSelection(event->location()) && | 656 if (!GetRenderText()->IsPointInSelection(event->location())) |
| 641 MoveCursorTo(event->location(), false)) | 657 MoveCursorTo(event->location(), false); |
| 642 SchedulePaint(); | |
| 643 OnAfterUserAction(); | 658 OnAfterUserAction(); |
| 644 event->SetHandled(); | 659 event->SetHandled(); |
| 645 break; | 660 break; |
| 646 case ui::ET_GESTURE_SCROLL_UPDATE: | 661 case ui::ET_GESTURE_SCROLL_UPDATE: |
| 647 OnBeforeUserAction(); | 662 OnBeforeUserAction(); |
| 648 if (MoveCursorTo(event->location(), true)) | 663 MoveCursorTo(event->location(), true); |
| 649 SchedulePaint(); | |
| 650 OnAfterUserAction(); | 664 OnAfterUserAction(); |
| 651 event->SetHandled(); | 665 event->SetHandled(); |
| 652 break; | 666 break; |
| 653 case ui::ET_GESTURE_SCROLL_END: | 667 case ui::ET_GESTURE_SCROLL_END: |
| 654 case ui::ET_SCROLL_FLING_START: | 668 case ui::ET_SCROLL_FLING_START: |
| 655 CreateTouchSelectionControllerAndNotifyIt(); | 669 CreateTouchSelectionControllerAndNotifyIt(); |
| 656 event->SetHandled(); | 670 event->SetHandled(); |
| 657 break; | 671 break; |
| 658 case ui::ET_GESTURE_TAP: | 672 case ui::ET_GESTURE_TAP: |
| 659 if (event->details().tap_count() == 1) { | 673 if (event->details().tap_count() == 1) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 675 // |touch_selection_controller_|, hence we mark the event handled. | 689 // |touch_selection_controller_|, hence we mark the event handled. |
| 676 // Otherwise, the regular context menu will be shown by views). | 690 // Otherwise, the regular context menu will be shown by views). |
| 677 // If long press happens in selected text and touch drag drop is enabled, | 691 // If long press happens in selected text and touch drag drop is enabled, |
| 678 // we will turn off touch selection (if one exists) and let views do drag | 692 // we will turn off touch selection (if one exists) and let views do drag |
| 679 // drop. | 693 // drop. |
| 680 if (!GetRenderText()->IsPointInSelection(event->location())) { | 694 if (!GetRenderText()->IsPointInSelection(event->location())) { |
| 681 OnBeforeUserAction(); | 695 OnBeforeUserAction(); |
| 682 model_->SelectWord(); | 696 model_->SelectWord(); |
| 683 touch_selection_controller_.reset( | 697 touch_selection_controller_.reset( |
| 684 ui::TouchSelectionController::create(this)); | 698 ui::TouchSelectionController::create(this)); |
| 685 OnCaretBoundsChanged(); | 699 UpdateAfterChange(false, true); |
| 686 SchedulePaint(); | |
| 687 OnAfterUserAction(); | 700 OnAfterUserAction(); |
| 688 if (touch_selection_controller_) | 701 if (touch_selection_controller_) |
| 689 event->SetHandled(); | 702 event->SetHandled(); |
| 690 } else if (switches::IsTouchDragDropEnabled()) { | 703 } else if (switches::IsTouchDragDropEnabled()) { |
| 691 initiating_drag_ = true; | 704 initiating_drag_ = true; |
| 692 touch_selection_controller_.reset(); | 705 touch_selection_controller_.reset(); |
| 693 } else { | 706 } else { |
| 694 if (!touch_selection_controller_) | 707 if (!touch_selection_controller_) |
| 695 CreateTouchSelectionControllerAndNotifyIt(); | 708 CreateTouchSelectionControllerAndNotifyIt(); |
| 696 if (touch_selection_controller_) | 709 if (touch_selection_controller_) |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 885 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) | 898 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) |
| 886 return; | 899 return; |
| 887 | 900 |
| 888 gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start); | 901 gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start); |
| 889 gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end); | 902 gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end); |
| 890 gfx::SelectionModel selection( | 903 gfx::SelectionModel selection( |
| 891 gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()), | 904 gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()), |
| 892 end_caret.caret_affinity()); | 905 end_caret.caret_affinity()); |
| 893 | 906 |
| 894 OnBeforeUserAction(); | 907 OnBeforeUserAction(); |
| 895 model_->SelectSelectionModel(selection); | 908 SelectSelectionModel(selection); |
| 896 OnCaretBoundsChanged(); | |
| 897 SchedulePaint(); | |
| 898 OnAfterUserAction(); | 909 OnAfterUserAction(); |
| 899 } | 910 } |
| 900 | 911 |
| 901 void Textfield::MoveCaretTo(const gfx::Point& point) { | 912 void Textfield::MoveCaretTo(const gfx::Point& point) { |
| 902 SelectRect(point, point); | 913 SelectRect(point, point); |
| 903 } | 914 } |
| 904 | 915 |
| 905 void Textfield::GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) { | 916 void Textfield::GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) { |
| 906 gfx::RenderText* render_text = GetRenderText(); | 917 gfx::RenderText* render_text = GetRenderText(); |
| 907 const gfx::SelectionModel& sel = render_text->selection_model(); | 918 const gfx::SelectionModel& sel = render_text->selection_model(); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 971 ui::Accelerator* accelerator) { | 982 ui::Accelerator* accelerator) { |
| 972 return false; | 983 return false; |
| 973 } | 984 } |
| 974 | 985 |
| 975 void Textfield::ExecuteCommand(int command_id, int event_flags) { | 986 void Textfield::ExecuteCommand(int command_id, int event_flags) { |
| 976 touch_selection_controller_.reset(); | 987 touch_selection_controller_.reset(); |
| 977 if (!IsCommandIdEnabled(command_id)) | 988 if (!IsCommandIdEnabled(command_id)) |
| 978 return; | 989 return; |
| 979 | 990 |
| 980 bool text_changed = false; | 991 bool text_changed = false; |
| 992 OnBeforeUserAction(); | |
| 981 switch (command_id) { | 993 switch (command_id) { |
| 982 case IDS_APP_UNDO: | 994 case IDS_APP_UNDO: |
| 983 OnBeforeUserAction(); | |
| 984 text_changed = model_->Undo(); | 995 text_changed = model_->Undo(); |
| 985 UpdateAfterChange(text_changed, text_changed); | |
| 986 OnAfterUserAction(); | |
| 987 break; | 996 break; |
| 988 case IDS_APP_CUT: | 997 case IDS_APP_CUT: |
| 989 OnBeforeUserAction(); | |
| 990 text_changed = Cut(); | 998 text_changed = Cut(); |
| 991 UpdateAfterChange(text_changed, text_changed); | |
| 992 OnAfterUserAction(); | |
| 993 break; | 999 break; |
| 994 case IDS_APP_COPY: | 1000 case IDS_APP_COPY: |
| 995 OnBeforeUserAction(); | |
| 996 Copy(); | 1001 Copy(); |
| 997 OnAfterUserAction(); | |
| 998 break; | 1002 break; |
| 999 case IDS_APP_PASTE: | 1003 case IDS_APP_PASTE: |
| 1000 OnBeforeUserAction(); | |
| 1001 text_changed = Paste(); | 1004 text_changed = Paste(); |
| 1002 UpdateAfterChange(text_changed, text_changed); | |
| 1003 OnAfterUserAction(); | |
| 1004 break; | 1005 break; |
| 1005 case IDS_APP_DELETE: | 1006 case IDS_APP_DELETE: |
| 1006 OnBeforeUserAction(); | |
| 1007 text_changed = model_->Delete(); | 1007 text_changed = model_->Delete(); |
| 1008 UpdateAfterChange(text_changed, text_changed); | |
| 1009 OnAfterUserAction(); | |
| 1010 break; | 1008 break; |
| 1011 case IDS_APP_SELECT_ALL: | 1009 case IDS_APP_SELECT_ALL: |
| 1012 OnBeforeUserAction(); | |
| 1013 SelectAll(false); | 1010 SelectAll(false); |
| 1014 UpdateAfterChange(false, true); | |
| 1015 OnAfterUserAction(); | |
| 1016 break; | 1011 break; |
| 1017 default: | 1012 default: |
| 1018 NOTREACHED(); | 1013 NOTREACHED(); |
| 1019 break; | 1014 break; |
| 1020 } | 1015 } |
| 1016 UpdateAfterChange(text_changed, text_changed); | |
| 1017 OnAfterUserAction(); | |
| 1021 } | 1018 } |
| 1022 | 1019 |
| 1023 //////////////////////////////////////////////////////////////////////////////// | 1020 //////////////////////////////////////////////////////////////////////////////// |
| 1024 // Textfield, ui::TextInputClient overrides: | 1021 // Textfield, ui::TextInputClient overrides: |
| 1025 | 1022 |
| 1026 void Textfield::SetCompositionText(const ui::CompositionText& composition) { | 1023 void Textfield::SetCompositionText(const ui::CompositionText& composition) { |
| 1027 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) | 1024 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) |
| 1028 return; | 1025 return; |
| 1029 | 1026 |
| 1030 OnBeforeUserAction(); | 1027 OnBeforeUserAction(); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1186 bool Textfield::GetSelectionRange(gfx::Range* range) const { | 1183 bool Textfield::GetSelectionRange(gfx::Range* range) const { |
| 1187 if (!ImeEditingAllowed()) | 1184 if (!ImeEditingAllowed()) |
| 1188 return false; | 1185 return false; |
| 1189 *range = GetRenderText()->selection(); | 1186 *range = GetRenderText()->selection(); |
| 1190 return true; | 1187 return true; |
| 1191 } | 1188 } |
| 1192 | 1189 |
| 1193 bool Textfield::SetSelectionRange(const gfx::Range& range) { | 1190 bool Textfield::SetSelectionRange(const gfx::Range& range) { |
| 1194 if (!ImeEditingAllowed() || !range.IsValid()) | 1191 if (!ImeEditingAllowed() || !range.IsValid()) |
| 1195 return false; | 1192 return false; |
| 1196 | |
| 1197 OnBeforeUserAction(); | 1193 OnBeforeUserAction(); |
| 1198 SelectRange(range); | 1194 SelectRange(range); |
| 1199 OnAfterUserAction(); | 1195 OnAfterUserAction(); |
| 1200 return true; | 1196 return true; |
| 1201 } | 1197 } |
| 1202 | 1198 |
| 1203 bool Textfield::DeleteRange(const gfx::Range& range) { | 1199 bool Textfield::DeleteRange(const gfx::Range& range) { |
| 1204 if (!ImeEditingAllowed() || range.is_empty()) | 1200 if (!ImeEditingAllowed() || range.is_empty()) |
| 1205 return false; | 1201 return false; |
| 1206 | 1202 |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1350 !HasSelection()); | 1346 !HasSelection()); |
| 1351 render_text->Draw(canvas); | 1347 render_text->Draw(canvas); |
| 1352 | 1348 |
| 1353 // Draw the detached drop cursor that marks where the text will be dropped. | 1349 // Draw the detached drop cursor that marks where the text will be dropped. |
| 1354 if (drop_cursor_visible_) | 1350 if (drop_cursor_visible_) |
| 1355 render_text->DrawCursor(canvas, drop_cursor_position_); | 1351 render_text->DrawCursor(canvas, drop_cursor_position_); |
| 1356 | 1352 |
| 1357 canvas->Restore(); | 1353 canvas->Restore(); |
| 1358 } | 1354 } |
| 1359 | 1355 |
| 1360 bool Textfield::MoveCursorTo(const gfx::Point& point, bool select) { | 1356 void Textfield::MoveCursorTo(const gfx::Point& point, bool select) { |
| 1361 if (!model_->MoveCursorTo(point, select)) | 1357 if (model_->MoveCursorTo(point, select)) |
| 1362 return false; | 1358 UpdateAfterChange(false, true); |
| 1363 OnCaretBoundsChanged(); | |
| 1364 return true; | |
| 1365 } | 1359 } |
| 1366 | 1360 |
| 1367 void Textfield::OnCaretBoundsChanged() { | 1361 void Textfield::OnCaretBoundsChanged() { |
| 1368 if (GetInputMethod()) | 1362 if (GetInputMethod()) |
| 1369 GetInputMethod()->OnCaretBoundsChanged(this); | 1363 GetInputMethod()->OnCaretBoundsChanged(this); |
| 1370 if (touch_selection_controller_) | 1364 if (touch_selection_controller_) |
| 1371 touch_selection_controller_->SelectionChanged(); | 1365 touch_selection_controller_->SelectionChanged(); |
| 1372 } | 1366 } |
| 1373 | 1367 |
| 1374 void Textfield::OnBeforeUserAction() { | 1368 void Textfield::OnBeforeUserAction() { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1463 | 1457 |
| 1464 void Textfield::CreateTouchSelectionControllerAndNotifyIt() { | 1458 void Textfield::CreateTouchSelectionControllerAndNotifyIt() { |
| 1465 if (!touch_selection_controller_) { | 1459 if (!touch_selection_controller_) { |
| 1466 touch_selection_controller_.reset( | 1460 touch_selection_controller_.reset( |
| 1467 ui::TouchSelectionController::create(this)); | 1461 ui::TouchSelectionController::create(this)); |
| 1468 } | 1462 } |
| 1469 if (touch_selection_controller_) | 1463 if (touch_selection_controller_) |
| 1470 touch_selection_controller_->SelectionChanged(); | 1464 touch_selection_controller_->SelectionChanged(); |
| 1471 } | 1465 } |
| 1472 | 1466 |
| 1467 void Textfield::PasteSelectionClipboard(const ui::MouseEvent& event) { | |
| 1468 DCHECK(event.IsOnlyMiddleMouseButton()); | |
| 1469 DCHECK(!read_only()); | |
| 1470 base::string16 selection_clipboard_text; | |
| 1471 ui::Clipboard::GetForCurrentThread()->ReadText( | |
| 1472 ui::CLIPBOARD_TYPE_SELECTION, &selection_clipboard_text); | |
| 1473 if (!selection_clipboard_text.empty()) { | |
| 1474 OnBeforeUserAction(); | |
| 1475 gfx::Range range = GetSelectionModel().selection(); | |
| 1476 gfx::LogicalCursorDirection affinity = GetSelectionModel().caret_affinity(); | |
| 1477 const gfx::SelectionModel mouse = | |
| 1478 GetRenderText()->FindCursorPosition(event.location()); | |
| 1479 model_->MoveCursorTo(mouse); | |
| 1480 model_->InsertText(selection_clipboard_text); | |
| 1481 // Update the new selection range as needed. | |
| 1482 if (range.GetMin() >= mouse.caret_pos()) { | |
| 1483 const size_t length = selection_clipboard_text.length(); | |
| 1484 range = gfx::Range(range.start() + length, range.end() + length); | |
| 1485 } | |
| 1486 model_->MoveCursorTo(gfx::SelectionModel(range, affinity)); | |
| 1487 UpdateAfterChange(true, true); | |
| 1488 OnAfterUserAction(); | |
| 1489 } | |
| 1490 } | |
| 1491 | |
| 1473 } // namespace views | 1492 } // namespace views |
| OLD | NEW |