| 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 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 OnCaretBoundsChanged(); | 145 OnCaretBoundsChanged(); |
| 145 SchedulePaint(); | 146 SchedulePaint(); |
| 146 } | 147 } |
| 147 | 148 |
| 148 base::i18n::TextDirection Textfield::GetTextDirection() const { | 149 base::i18n::TextDirection Textfield::GetTextDirection() const { |
| 149 return GetRenderText()->GetTextDirection(); | 150 return GetRenderText()->GetTextDirection(); |
| 150 } | 151 } |
| 151 | 152 |
| 152 void Textfield::SelectAll(bool reversed) { | 153 void Textfield::SelectAll(bool reversed) { |
| 153 model_->SelectAll(reversed); | 154 model_->SelectAll(reversed); |
| 154 OnCaretBoundsChanged(); | 155 UpdateSelectionClipboard(); |
| 155 SchedulePaint(); | 156 UpdateAfterChange(false, true); |
| 156 } | 157 } |
| 157 | 158 |
| 158 base::string16 Textfield::GetSelectedText() const { | 159 base::string16 Textfield::GetSelectedText() const { |
| 159 return model_->GetSelectedText(); | 160 return model_->GetSelectedText(); |
| 160 } | 161 } |
| 161 | 162 |
| 162 void Textfield::ClearSelection() { | 163 void Textfield::ClearSelection() { |
| 163 model_->ClearSelection(); | 164 model_->ClearSelection(); |
| 164 OnCaretBoundsChanged(); | 165 UpdateAfterChange(false, true); |
| 165 SchedulePaint(); | |
| 166 } | 166 } |
| 167 | 167 |
| 168 bool Textfield::HasSelection() const { | 168 bool Textfield::HasSelection() const { |
| 169 return !GetSelectedRange().is_empty(); | 169 return !GetSelectedRange().is_empty(); |
| 170 } | 170 } |
| 171 | 171 |
| 172 SkColor Textfield::GetTextColor() const { | 172 SkColor Textfield::GetTextColor() const { |
| 173 if (!use_default_text_color_) | 173 if (!use_default_text_color_) |
| 174 return text_color_; | 174 return text_color_; |
| 175 | 175 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 bool Textfield::IsIMEComposing() const { | 234 bool Textfield::IsIMEComposing() const { |
| 235 return model_->HasCompositionText(); | 235 return model_->HasCompositionText(); |
| 236 } | 236 } |
| 237 | 237 |
| 238 const gfx::Range& Textfield::GetSelectedRange() const { | 238 const gfx::Range& Textfield::GetSelectedRange() const { |
| 239 return GetRenderText()->selection(); | 239 return GetRenderText()->selection(); |
| 240 } | 240 } |
| 241 | 241 |
| 242 void Textfield::SelectRange(const gfx::Range& range) { | 242 void Textfield::SelectRange(const gfx::Range& range) { |
| 243 model_->SelectRange(range); | 243 model_->SelectRange(range); |
| 244 OnCaretBoundsChanged(); | 244 UpdateAfterChange(false, true); |
| 245 SchedulePaint(); | |
| 246 NotifyAccessibilityEvent( | |
| 247 ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true); | |
| 248 } | 245 } |
| 249 | 246 |
| 250 const gfx::SelectionModel& Textfield::GetSelectionModel() const { | 247 const gfx::SelectionModel& Textfield::GetSelectionModel() const { |
| 251 return GetRenderText()->selection_model(); | 248 return GetRenderText()->selection_model(); |
| 252 } | 249 } |
| 253 | 250 |
| 254 void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) { | 251 void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) { |
| 255 model_->SelectSelectionModel(sel); | 252 model_->SelectSelectionModel(sel); |
| 256 OnCaretBoundsChanged(); | 253 UpdateAfterChange(false, true); |
| 257 SchedulePaint(); | |
| 258 } | 254 } |
| 259 | 255 |
| 260 size_t Textfield::GetCursorPosition() const { | 256 size_t Textfield::GetCursorPosition() const { |
| 261 return model_->GetCursorPosition(); | 257 return model_->GetCursorPosition(); |
| 262 } | 258 } |
| 263 | 259 |
| 264 void Textfield::SetColor(SkColor value) { | 260 void Textfield::SetColor(SkColor value) { |
| 265 GetRenderText()->SetColor(value); | 261 GetRenderText()->SetColor(value); |
| 266 SchedulePaint(); | 262 SchedulePaint(); |
| 267 } | 263 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 else if (control && shift && !alt && editable) | 359 else if (control && shift && !alt && editable) |
| 364 cursor_changed = text_changed = model_->Redo(); | 360 cursor_changed = text_changed = model_->Redo(); |
| 365 break; | 361 break; |
| 366 case ui::VKEY_Y: | 362 case ui::VKEY_Y: |
| 367 if (control && !alt && editable) | 363 if (control && !alt && editable) |
| 368 cursor_changed = text_changed = model_->Redo(); | 364 cursor_changed = text_changed = model_->Redo(); |
| 369 break; | 365 break; |
| 370 case ui::VKEY_A: | 366 case ui::VKEY_A: |
| 371 if (control && !alt) { | 367 if (control && !alt) { |
| 372 model_->SelectAll(false); | 368 model_->SelectAll(false); |
| 369 UpdateSelectionClipboard(); |
| 373 cursor_changed = true; | 370 cursor_changed = true; |
| 374 } | 371 } |
| 375 break; | 372 break; |
| 376 case ui::VKEY_X: | 373 case ui::VKEY_X: |
| 377 if (control && !alt && editable && readable) | 374 if (control && !alt && editable && readable) |
| 378 cursor_changed = text_changed = Cut(); | 375 cursor_changed = text_changed = Cut(); |
| 379 break; | 376 break; |
| 380 case ui::VKEY_C: | 377 case ui::VKEY_C: |
| 381 if (control && !alt && readable) | 378 if (control && !alt && readable) |
| 382 Copy(); | 379 Copy(); |
| 383 break; | 380 break; |
| 384 case ui::VKEY_V: | 381 case ui::VKEY_V: |
| 385 if (control && !alt && editable) | 382 if (control && !alt && editable) |
| 386 cursor_changed = text_changed = Paste(); | 383 cursor_changed = text_changed = Paste(); |
| 387 break; | 384 break; |
| 388 case ui::VKEY_RIGHT: | 385 case ui::VKEY_RIGHT: |
| 389 case ui::VKEY_LEFT: { | 386 case ui::VKEY_LEFT: { |
| 390 // We should ignore the alt-left/right keys because alt key doesn't make | 387 // 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 | 388 // any special effects for them and they can be shortcut keys such like |
| 392 // forward/back of the browser history. | 389 // forward/back of the browser history. |
| 393 if (alt) | 390 if (alt) |
| 394 break; | 391 break; |
| 395 const gfx::Range selection_range = render_text->selection(); | 392 const gfx::Range selection_range = render_text->selection(); |
| 396 model_->MoveCursor( | 393 model_->MoveCursor( |
| 397 control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, | 394 control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, |
| 398 (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT, | 395 (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT, |
| 399 shift); | 396 shift); |
| 397 UpdateSelectionClipboard(); |
| 400 cursor_changed = render_text->selection() != selection_range; | 398 cursor_changed = render_text->selection() != selection_range; |
| 401 break; | 399 break; |
| 402 } | 400 } |
| 403 case ui::VKEY_END: | 401 case ui::VKEY_END: |
| 404 case ui::VKEY_HOME: | 402 case ui::VKEY_HOME: |
| 405 if ((key_code == ui::VKEY_HOME) == | 403 if ((key_code == ui::VKEY_HOME) == |
| 406 (render_text->GetTextDirection() == base::i18n::RIGHT_TO_LEFT)) | 404 (render_text->GetTextDirection() == base::i18n::RIGHT_TO_LEFT)) |
| 407 model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, shift); | 405 model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, shift); |
| 408 else | 406 else |
| 409 model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, shift); | 407 model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, shift); |
| 408 UpdateSelectionClipboard(); |
| 410 cursor_changed = true; | 409 cursor_changed = true; |
| 411 break; | 410 break; |
| 412 case ui::VKEY_BACK: | 411 case ui::VKEY_BACK: |
| 413 case ui::VKEY_DELETE: | 412 case ui::VKEY_DELETE: |
| 414 if (!editable) | 413 if (!editable) |
| 415 break; | 414 break; |
| 416 if (!model_->HasSelection()) { | 415 if (!model_->HasSelection()) { |
| 417 gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ? | 416 gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ? |
| 418 gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT; | 417 gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT; |
| 419 if (shift && control) { | 418 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. | 452 // We must have input method in order to support text input. |
| 454 DCHECK(GetInputMethod()); | 453 DCHECK(GetInputMethod()); |
| 455 UpdateAfterChange(text_changed, cursor_changed); | 454 UpdateAfterChange(text_changed, cursor_changed); |
| 456 OnAfterUserAction(); | 455 OnAfterUserAction(); |
| 457 return (text_changed || cursor_changed); | 456 return (text_changed || cursor_changed); |
| 458 } | 457 } |
| 459 return false; | 458 return false; |
| 460 } | 459 } |
| 461 | 460 |
| 462 bool Textfield::OnMousePressed(const ui::MouseEvent& event) { | 461 bool Textfield::OnMousePressed(const ui::MouseEvent& event) { |
| 463 OnBeforeUserAction(); | |
| 464 TrackMouseClicks(event); | 462 TrackMouseClicks(event); |
| 465 | 463 |
| 466 if (!controller_ || !controller_->HandleMouseEvent(this, event)) { | 464 if (!controller_ || !controller_->HandleMouseEvent(this, event)) { |
| 467 if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) | 465 if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) |
| 468 RequestFocus(); | 466 RequestFocus(); |
| 469 | 467 |
| 470 if (event.IsOnlyLeftMouseButton()) { | 468 if (event.IsOnlyLeftMouseButton()) { |
| 469 OnBeforeUserAction(); |
| 471 initiating_drag_ = false; | 470 initiating_drag_ = false; |
| 472 bool can_drag = true; | |
| 473 | |
| 474 switch (aggregated_clicks_) { | 471 switch (aggregated_clicks_) { |
| 475 case 0: | 472 case 0: |
| 476 if (can_drag && | 473 if (GetRenderText()->IsPointInSelection(event.location())) |
| 477 GetRenderText()->IsPointInSelection(event.location())) { | |
| 478 initiating_drag_ = true; | 474 initiating_drag_ = true; |
| 479 } else { | 475 else |
| 480 MoveCursorTo(event.location(), event.IsShiftDown()); | 476 MoveCursorTo(event.location(), event.IsShiftDown()); |
| 481 } | |
| 482 break; | 477 break; |
| 483 case 1: | 478 case 1: |
| 484 MoveCursorTo(event.location(), false); | 479 model_->MoveCursorTo(event.location(), false); |
| 485 model_->SelectWord(); | 480 model_->SelectWord(); |
| 481 UpdateAfterChange(false, true); |
| 486 double_click_word_ = GetRenderText()->selection(); | 482 double_click_word_ = GetRenderText()->selection(); |
| 487 OnCaretBoundsChanged(); | |
| 488 break; | 483 break; |
| 489 case 2: | 484 case 2: |
| 490 model_->SelectAll(false); | 485 SelectAll(false); |
| 491 OnCaretBoundsChanged(); | |
| 492 break; | 486 break; |
| 493 default: | 487 default: |
| 494 NOTREACHED(); | 488 NOTREACHED(); |
| 495 } | 489 } |
| 490 OnAfterUserAction(); |
| 496 } | 491 } |
| 497 SchedulePaint(); | 492 |
| 493 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 494 if (event.IsOnlyMiddleMouseButton()) { |
| 495 if (GetRenderText()->IsPointInSelection(event.location())) { |
| 496 OnBeforeUserAction(); |
| 497 ClearSelection(); |
| 498 ui::ScopedClipboardWriter( |
| 499 ui::Clipboard::GetForCurrentThread(), |
| 500 ui::CLIPBOARD_TYPE_SELECTION).WriteText(base::string16()); |
| 501 OnAfterUserAction(); |
| 502 } else if(!read_only()) { |
| 503 PasteSelectionClipboard(event); |
| 504 } |
| 505 } |
| 506 #endif |
| 498 } | 507 } |
| 499 | 508 |
| 500 OnAfterUserAction(); | |
| 501 touch_selection_controller_.reset(); | 509 touch_selection_controller_.reset(); |
| 502 return true; | 510 return true; |
| 503 } | 511 } |
| 504 | 512 |
| 505 bool Textfield::OnMouseDragged(const ui::MouseEvent& event) { | 513 bool Textfield::OnMouseDragged(const ui::MouseEvent& event) { |
| 506 // Don't adjust the cursor on a potential drag and drop, or if the mouse | 514 // 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. | 515 // movement from the last mouse click does not exceed the drag threshold. |
| 508 if (initiating_drag_ || !event.IsOnlyLeftMouseButton() || | 516 if (initiating_drag_ || !event.IsOnlyLeftMouseButton() || |
| 509 !ExceededDragThreshold(event.location() - last_click_location_)) { | 517 !ExceededDragThreshold(event.location() - last_click_location_)) { |
| 510 return true; | 518 return true; |
| 511 } | 519 } |
| 512 | 520 |
| 513 if (!event.IsOnlyRightMouseButton()) { | 521 OnBeforeUserAction(); |
| 514 OnBeforeUserAction(); | 522 model_->MoveCursorTo(event.location(), true); |
| 515 MoveCursorTo(event.location(), true); | 523 if (aggregated_clicks_ == 1) { |
| 516 if (aggregated_clicks_ == 1) { | 524 model_->SelectWord(); |
| 517 model_->SelectWord(); | 525 // Expand the selection so the initially selected word remains selected. |
| 518 // Expand the selection so the initially selected word remains selected. | 526 gfx::Range selection = GetRenderText()->selection(); |
| 519 gfx::Range selection = GetRenderText()->selection(); | 527 const size_t min = std::min(selection.GetMin(), |
| 520 const size_t min = std::min(selection.GetMin(), | 528 double_click_word_.GetMin()); |
| 521 double_click_word_.GetMin()); | 529 const size_t max = std::max(selection.GetMax(), |
| 522 const size_t max = std::max(selection.GetMax(), | 530 double_click_word_.GetMax()); |
| 523 double_click_word_.GetMax()); | 531 const bool reversed = selection.is_reversed(); |
| 524 const bool reversed = selection.is_reversed(); | 532 selection.set_start(reversed ? max : min); |
| 525 selection.set_start(reversed ? max : min); | 533 selection.set_end(reversed ? min : max); |
| 526 selection.set_end(reversed ? min : max); | 534 model_->SelectRange(selection); |
| 527 model_->SelectRange(selection); | |
| 528 } | |
| 529 SchedulePaint(); | |
| 530 OnAfterUserAction(); | |
| 531 } | 535 } |
| 536 UpdateAfterChange(false, true); |
| 537 OnAfterUserAction(); |
| 532 return true; | 538 return true; |
| 533 } | 539 } |
| 534 | 540 |
| 535 void Textfield::OnMouseReleased(const ui::MouseEvent& event) { | 541 void Textfield::OnMouseReleased(const ui::MouseEvent& event) { |
| 536 OnBeforeUserAction(); | 542 OnBeforeUserAction(); |
| 537 // Cancel suspected drag initiations, the user was clicking in the selection. | 543 // Cancel suspected drag initiations, the user was clicking in the selection. |
| 538 if (initiating_drag_ && MoveCursorTo(event.location(), false)) | 544 if (initiating_drag_) |
| 539 SchedulePaint(); | 545 MoveCursorTo(event.location(), false); |
| 540 initiating_drag_ = false; | 546 initiating_drag_ = false; |
| 547 UpdateSelectionClipboard(); |
| 541 OnAfterUserAction(); | 548 OnAfterUserAction(); |
| 542 } | 549 } |
| 543 | 550 |
| 544 void Textfield::OnFocus() { | 551 void Textfield::OnFocus() { |
| 545 GetRenderText()->set_focused(true); | 552 GetRenderText()->set_focused(true); |
| 546 cursor_visible_ = true; | 553 cursor_visible_ = true; |
| 547 SchedulePaint(); | 554 SchedulePaint(); |
| 548 GetInputMethod()->OnFocus(); | 555 GetInputMethod()->OnFocus(); |
| 549 OnCaretBoundsChanged(); | 556 OnCaretBoundsChanged(); |
| 550 | 557 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 630 #endif | 637 #endif |
| 631 } | 638 } |
| 632 | 639 |
| 633 void Textfield::OnGestureEvent(ui::GestureEvent* event) { | 640 void Textfield::OnGestureEvent(ui::GestureEvent* event) { |
| 634 switch (event->type()) { | 641 switch (event->type()) { |
| 635 case ui::ET_GESTURE_TAP_DOWN: | 642 case ui::ET_GESTURE_TAP_DOWN: |
| 636 OnBeforeUserAction(); | 643 OnBeforeUserAction(); |
| 637 RequestFocus(); | 644 RequestFocus(); |
| 638 // We don't deselect if the point is in the selection | 645 // We don't deselect if the point is in the selection |
| 639 // because TAP_DOWN may turn into a LONG_PRESS. | 646 // because TAP_DOWN may turn into a LONG_PRESS. |
| 640 if (!GetRenderText()->IsPointInSelection(event->location()) && | 647 if (!GetRenderText()->IsPointInSelection(event->location())) |
| 641 MoveCursorTo(event->location(), false)) | 648 MoveCursorTo(event->location(), false); |
| 642 SchedulePaint(); | |
| 643 OnAfterUserAction(); | 649 OnAfterUserAction(); |
| 644 event->SetHandled(); | 650 event->SetHandled(); |
| 645 break; | 651 break; |
| 646 case ui::ET_GESTURE_SCROLL_UPDATE: | 652 case ui::ET_GESTURE_SCROLL_UPDATE: |
| 647 OnBeforeUserAction(); | 653 OnBeforeUserAction(); |
| 648 if (MoveCursorTo(event->location(), true)) | 654 MoveCursorTo(event->location(), true); |
| 649 SchedulePaint(); | |
| 650 OnAfterUserAction(); | 655 OnAfterUserAction(); |
| 651 event->SetHandled(); | 656 event->SetHandled(); |
| 652 break; | 657 break; |
| 653 case ui::ET_GESTURE_SCROLL_END: | 658 case ui::ET_GESTURE_SCROLL_END: |
| 654 case ui::ET_SCROLL_FLING_START: | 659 case ui::ET_SCROLL_FLING_START: |
| 655 CreateTouchSelectionControllerAndNotifyIt(); | 660 CreateTouchSelectionControllerAndNotifyIt(); |
| 656 event->SetHandled(); | 661 event->SetHandled(); |
| 657 break; | 662 break; |
| 658 case ui::ET_GESTURE_TAP: | 663 case ui::ET_GESTURE_TAP: |
| 659 if (event->details().tap_count() == 1) { | 664 if (event->details().tap_count() == 1) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 675 // |touch_selection_controller_|, hence we mark the event handled. | 680 // |touch_selection_controller_|, hence we mark the event handled. |
| 676 // Otherwise, the regular context menu will be shown by views). | 681 // Otherwise, the regular context menu will be shown by views). |
| 677 // If long press happens in selected text and touch drag drop is enabled, | 682 // 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 | 683 // we will turn off touch selection (if one exists) and let views do drag |
| 679 // drop. | 684 // drop. |
| 680 if (!GetRenderText()->IsPointInSelection(event->location())) { | 685 if (!GetRenderText()->IsPointInSelection(event->location())) { |
| 681 OnBeforeUserAction(); | 686 OnBeforeUserAction(); |
| 682 model_->SelectWord(); | 687 model_->SelectWord(); |
| 683 touch_selection_controller_.reset( | 688 touch_selection_controller_.reset( |
| 684 ui::TouchSelectionController::create(this)); | 689 ui::TouchSelectionController::create(this)); |
| 685 OnCaretBoundsChanged(); | 690 UpdateAfterChange(false, true); |
| 686 SchedulePaint(); | |
| 687 OnAfterUserAction(); | 691 OnAfterUserAction(); |
| 688 if (touch_selection_controller_) | 692 if (touch_selection_controller_) |
| 689 event->SetHandled(); | 693 event->SetHandled(); |
| 690 } else if (switches::IsTouchDragDropEnabled()) { | 694 } else if (switches::IsTouchDragDropEnabled()) { |
| 691 initiating_drag_ = true; | 695 initiating_drag_ = true; |
| 692 touch_selection_controller_.reset(); | 696 touch_selection_controller_.reset(); |
| 693 } else { | 697 } else { |
| 694 if (!touch_selection_controller_) | 698 if (!touch_selection_controller_) |
| 695 CreateTouchSelectionControllerAndNotifyIt(); | 699 CreateTouchSelectionControllerAndNotifyIt(); |
| 696 if (touch_selection_controller_) | 700 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) | 889 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) |
| 886 return; | 890 return; |
| 887 | 891 |
| 888 gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start); | 892 gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start); |
| 889 gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end); | 893 gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end); |
| 890 gfx::SelectionModel selection( | 894 gfx::SelectionModel selection( |
| 891 gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()), | 895 gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()), |
| 892 end_caret.caret_affinity()); | 896 end_caret.caret_affinity()); |
| 893 | 897 |
| 894 OnBeforeUserAction(); | 898 OnBeforeUserAction(); |
| 895 model_->SelectSelectionModel(selection); | 899 SelectSelectionModel(selection); |
| 896 OnCaretBoundsChanged(); | |
| 897 SchedulePaint(); | |
| 898 OnAfterUserAction(); | 900 OnAfterUserAction(); |
| 899 } | 901 } |
| 900 | 902 |
| 901 void Textfield::MoveCaretTo(const gfx::Point& point) { | 903 void Textfield::MoveCaretTo(const gfx::Point& point) { |
| 902 SelectRect(point, point); | 904 SelectRect(point, point); |
| 903 } | 905 } |
| 904 | 906 |
| 905 void Textfield::GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) { | 907 void Textfield::GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) { |
| 906 gfx::RenderText* render_text = GetRenderText(); | 908 gfx::RenderText* render_text = GetRenderText(); |
| 907 const gfx::SelectionModel& sel = render_text->selection_model(); | 909 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) { | 973 ui::Accelerator* accelerator) { |
| 972 return false; | 974 return false; |
| 973 } | 975 } |
| 974 | 976 |
| 975 void Textfield::ExecuteCommand(int command_id, int event_flags) { | 977 void Textfield::ExecuteCommand(int command_id, int event_flags) { |
| 976 touch_selection_controller_.reset(); | 978 touch_selection_controller_.reset(); |
| 977 if (!IsCommandIdEnabled(command_id)) | 979 if (!IsCommandIdEnabled(command_id)) |
| 978 return; | 980 return; |
| 979 | 981 |
| 980 bool text_changed = false; | 982 bool text_changed = false; |
| 983 OnBeforeUserAction(); |
| 981 switch (command_id) { | 984 switch (command_id) { |
| 982 case IDS_APP_UNDO: | 985 case IDS_APP_UNDO: |
| 983 OnBeforeUserAction(); | |
| 984 text_changed = model_->Undo(); | 986 text_changed = model_->Undo(); |
| 985 UpdateAfterChange(text_changed, text_changed); | |
| 986 OnAfterUserAction(); | |
| 987 break; | 987 break; |
| 988 case IDS_APP_CUT: | 988 case IDS_APP_CUT: |
| 989 OnBeforeUserAction(); | |
| 990 text_changed = Cut(); | 989 text_changed = Cut(); |
| 991 UpdateAfterChange(text_changed, text_changed); | |
| 992 OnAfterUserAction(); | |
| 993 break; | 990 break; |
| 994 case IDS_APP_COPY: | 991 case IDS_APP_COPY: |
| 995 OnBeforeUserAction(); | |
| 996 Copy(); | 992 Copy(); |
| 997 OnAfterUserAction(); | |
| 998 break; | 993 break; |
| 999 case IDS_APP_PASTE: | 994 case IDS_APP_PASTE: |
| 1000 OnBeforeUserAction(); | |
| 1001 text_changed = Paste(); | 995 text_changed = Paste(); |
| 1002 UpdateAfterChange(text_changed, text_changed); | |
| 1003 OnAfterUserAction(); | |
| 1004 break; | 996 break; |
| 1005 case IDS_APP_DELETE: | 997 case IDS_APP_DELETE: |
| 1006 OnBeforeUserAction(); | |
| 1007 text_changed = model_->Delete(); | 998 text_changed = model_->Delete(); |
| 1008 UpdateAfterChange(text_changed, text_changed); | |
| 1009 OnAfterUserAction(); | |
| 1010 break; | 999 break; |
| 1011 case IDS_APP_SELECT_ALL: | 1000 case IDS_APP_SELECT_ALL: |
| 1012 OnBeforeUserAction(); | |
| 1013 SelectAll(false); | 1001 SelectAll(false); |
| 1014 UpdateAfterChange(false, true); | |
| 1015 OnAfterUserAction(); | |
| 1016 break; | 1002 break; |
| 1017 default: | 1003 default: |
| 1018 NOTREACHED(); | 1004 NOTREACHED(); |
| 1019 break; | 1005 break; |
| 1020 } | 1006 } |
| 1007 UpdateAfterChange(text_changed, text_changed); |
| 1008 OnAfterUserAction(); |
| 1021 } | 1009 } |
| 1022 | 1010 |
| 1023 //////////////////////////////////////////////////////////////////////////////// | 1011 //////////////////////////////////////////////////////////////////////////////// |
| 1024 // Textfield, ui::TextInputClient overrides: | 1012 // Textfield, ui::TextInputClient overrides: |
| 1025 | 1013 |
| 1026 void Textfield::SetCompositionText(const ui::CompositionText& composition) { | 1014 void Textfield::SetCompositionText(const ui::CompositionText& composition) { |
| 1027 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) | 1015 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) |
| 1028 return; | 1016 return; |
| 1029 | 1017 |
| 1030 OnBeforeUserAction(); | 1018 OnBeforeUserAction(); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1186 bool Textfield::GetSelectionRange(gfx::Range* range) const { | 1174 bool Textfield::GetSelectionRange(gfx::Range* range) const { |
| 1187 if (!ImeEditingAllowed()) | 1175 if (!ImeEditingAllowed()) |
| 1188 return false; | 1176 return false; |
| 1189 *range = GetRenderText()->selection(); | 1177 *range = GetRenderText()->selection(); |
| 1190 return true; | 1178 return true; |
| 1191 } | 1179 } |
| 1192 | 1180 |
| 1193 bool Textfield::SetSelectionRange(const gfx::Range& range) { | 1181 bool Textfield::SetSelectionRange(const gfx::Range& range) { |
| 1194 if (!ImeEditingAllowed() || !range.IsValid()) | 1182 if (!ImeEditingAllowed() || !range.IsValid()) |
| 1195 return false; | 1183 return false; |
| 1196 | |
| 1197 OnBeforeUserAction(); | 1184 OnBeforeUserAction(); |
| 1198 SelectRange(range); | 1185 SelectRange(range); |
| 1199 OnAfterUserAction(); | 1186 OnAfterUserAction(); |
| 1200 return true; | 1187 return true; |
| 1201 } | 1188 } |
| 1202 | 1189 |
| 1203 bool Textfield::DeleteRange(const gfx::Range& range) { | 1190 bool Textfield::DeleteRange(const gfx::Range& range) { |
| 1204 if (!ImeEditingAllowed() || range.is_empty()) | 1191 if (!ImeEditingAllowed() || range.is_empty()) |
| 1205 return false; | 1192 return false; |
| 1206 | 1193 |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1350 !HasSelection()); | 1337 !HasSelection()); |
| 1351 render_text->Draw(canvas); | 1338 render_text->Draw(canvas); |
| 1352 | 1339 |
| 1353 // Draw the detached drop cursor that marks where the text will be dropped. | 1340 // Draw the detached drop cursor that marks where the text will be dropped. |
| 1354 if (drop_cursor_visible_) | 1341 if (drop_cursor_visible_) |
| 1355 render_text->DrawCursor(canvas, drop_cursor_position_); | 1342 render_text->DrawCursor(canvas, drop_cursor_position_); |
| 1356 | 1343 |
| 1357 canvas->Restore(); | 1344 canvas->Restore(); |
| 1358 } | 1345 } |
| 1359 | 1346 |
| 1360 bool Textfield::MoveCursorTo(const gfx::Point& point, bool select) { | 1347 void Textfield::MoveCursorTo(const gfx::Point& point, bool select) { |
| 1361 if (!model_->MoveCursorTo(point, select)) | 1348 if (model_->MoveCursorTo(point, select)) |
| 1362 return false; | 1349 UpdateAfterChange(false, true); |
| 1363 OnCaretBoundsChanged(); | |
| 1364 return true; | |
| 1365 } | 1350 } |
| 1366 | 1351 |
| 1367 void Textfield::OnCaretBoundsChanged() { | 1352 void Textfield::OnCaretBoundsChanged() { |
| 1368 if (GetInputMethod()) | 1353 if (GetInputMethod()) |
| 1369 GetInputMethod()->OnCaretBoundsChanged(this); | 1354 GetInputMethod()->OnCaretBoundsChanged(this); |
| 1370 if (touch_selection_controller_) | 1355 if (touch_selection_controller_) |
| 1371 touch_selection_controller_->SelectionChanged(); | 1356 touch_selection_controller_->SelectionChanged(); |
| 1372 } | 1357 } |
| 1373 | 1358 |
| 1374 void Textfield::OnBeforeUserAction() { | 1359 void Textfield::OnBeforeUserAction() { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1463 | 1448 |
| 1464 void Textfield::CreateTouchSelectionControllerAndNotifyIt() { | 1449 void Textfield::CreateTouchSelectionControllerAndNotifyIt() { |
| 1465 if (!touch_selection_controller_) { | 1450 if (!touch_selection_controller_) { |
| 1466 touch_selection_controller_.reset( | 1451 touch_selection_controller_.reset( |
| 1467 ui::TouchSelectionController::create(this)); | 1452 ui::TouchSelectionController::create(this)); |
| 1468 } | 1453 } |
| 1469 if (touch_selection_controller_) | 1454 if (touch_selection_controller_) |
| 1470 touch_selection_controller_->SelectionChanged(); | 1455 touch_selection_controller_->SelectionChanged(); |
| 1471 } | 1456 } |
| 1472 | 1457 |
| 1458 void Textfield::UpdateSelectionClipboard() const { |
| 1459 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 1460 if (HasSelection()) { |
| 1461 ui::ScopedClipboardWriter( |
| 1462 ui::Clipboard::GetForCurrentThread(), |
| 1463 ui::CLIPBOARD_TYPE_SELECTION).WriteText(GetSelectedText()); |
| 1464 } |
| 1465 #endif |
| 1466 } |
| 1467 |
| 1468 void Textfield::PasteSelectionClipboard(const ui::MouseEvent& event) { |
| 1469 DCHECK(event.IsOnlyMiddleMouseButton()); |
| 1470 DCHECK(!read_only()); |
| 1471 base::string16 selection_clipboard_text; |
| 1472 ui::Clipboard::GetForCurrentThread()->ReadText( |
| 1473 ui::CLIPBOARD_TYPE_SELECTION, &selection_clipboard_text); |
| 1474 if (!selection_clipboard_text.empty()) { |
| 1475 OnBeforeUserAction(); |
| 1476 gfx::Range range = GetSelectionModel().selection(); |
| 1477 gfx::LogicalCursorDirection affinity = GetSelectionModel().caret_affinity(); |
| 1478 const gfx::SelectionModel mouse = |
| 1479 GetRenderText()->FindCursorPosition(event.location()); |
| 1480 model_->MoveCursorTo(mouse); |
| 1481 model_->InsertText(selection_clipboard_text); |
| 1482 // Update the new selection range as needed. |
| 1483 if (range.GetMin() >= mouse.caret_pos()) { |
| 1484 const size_t length = selection_clipboard_text.length(); |
| 1485 range = gfx::Range(range.start() + length, range.end() + length); |
| 1486 } |
| 1487 model_->MoveCursorTo(gfx::SelectionModel(range, affinity)); |
| 1488 UpdateAfterChange(true, true); |
| 1489 OnAfterUserAction(); |
| 1490 } |
| 1491 } |
| 1492 |
| 1473 } // namespace views | 1493 } // namespace views |
| OLD | NEW |