Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: ui/views/controls/textfield/textfield.cc

Issue 73403002: Views Textfield: copy-on-select and paste-on-middle-click. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add UpdateSelectionClipboard; expand unit test; cleanup ExecuteCommand. Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « ui/views/controls/textfield/textfield.h ('k') | ui/views/controls/textfield/textfield_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698