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

Unified Diff: ui/views/controls/textfield/textfield.cc

Issue 2408623002: Views: Extract text selection code from Textfield. (Closed)
Patch Set: Check for |handles_selection_clipboard_| Created 4 years, 2 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 side-by-side diff with in-line comments
Download patch
Index: ui/views/controls/textfield/textfield.cc
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 4163c40a3742095f01fec3da7cf14d44db94aae4..835b10509babbaf1fe5147d13903fde02867f278 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -40,7 +40,6 @@
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/drag_utils.h"
-#include "ui/views/metrics.h"
#include "ui/views/native_cursor.h"
#include "ui/views/painter.h"
#include "ui/views/style/platform_style.h"
@@ -85,18 +84,6 @@ void ConvertRectToScreen(const View* src, gfx::Rect* r) {
r->set_origin(new_origin);
}
-// Get the drag selection timer delay, respecting animation scaling for testing.
-int GetDragSelectionDelay() {
- switch (ui::ScopedAnimationDurationScaleMode::duration_scale_mode()) {
- case ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION: return 100;
- case ui::ScopedAnimationDurationScaleMode::FAST_DURATION: return 25;
- case ui::ScopedAnimationDurationScaleMode::SLOW_DURATION: return 400;
- case ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION: return 1;
- case ui::ScopedAnimationDurationScaleMode::ZERO_DURATION: return 0;
- }
- return 100;
-}
-
// Get the default command for a given key |event|.
ui::TextEditCommand GetCommandForKeyEvent(const ui::KeyEvent& event) {
if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode())
@@ -259,7 +246,7 @@ Textfield::Textfield()
skip_input_method_cancel_composition_(false),
drop_cursor_visible_(false),
initiating_drag_(false),
- aggregated_clicks_(0),
+ selection_controller_(this),
drag_start_display_offset_(0),
touch_handles_hidden_due_to_scroll_(false),
use_focus_ring_(ui::MaterialDesignController::IsSecondaryUiMaterial()),
@@ -270,6 +257,11 @@ Textfield::Textfield()
View::SetBorder(std::unique_ptr<Border>(new FocusableBorder()));
SetFocusBehavior(FocusBehavior::ALWAYS);
+// On Linux, middle click should update or paste the selection clipboard.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ selection_controller_.set_handles_selection_clipboard(true);
+#endif
+
// These allow BrowserView to pass edit commands from the Chrome menu to us
// when we're focused by simply asking the FocusManager to
// ProcessAccelerator() with the relevant accelerators.
@@ -335,7 +327,8 @@ base::string16 Textfield::GetSelectedText() const {
void Textfield::SelectAll(bool reversed) {
model_->SelectAll(reversed);
- UpdateSelectionClipboard();
+ if (HasSelection() && performing_user_action_)
+ UpdateSelectionClipboard();
UpdateAfterChange(false, true);
}
@@ -545,10 +538,6 @@ void Textfield::SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
}
-bool Textfield::HasTextBeingDragged() {
- return initiating_drag_;
-}
-
////////////////////////////////////////////////////////////////////////////////
// Textfield, View overrides:
@@ -587,88 +576,31 @@ gfx::NativeCursor Textfield::GetCursor(const ui::MouseEvent& event) {
}
bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
- TrackMouseClicks(event);
-
- if (!controller_ || !controller_->HandleMouseEvent(this, event)) {
- if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) {
- RequestFocus();
- ShowImeIfNeeded();
- }
-
- if (event.IsOnlyLeftMouseButton()) {
- OnBeforeUserAction();
- initiating_drag_ = false;
- switch (aggregated_clicks_) {
- case 0:
- if (GetRenderText()->IsPointInSelection(event.location()))
- initiating_drag_ = true;
- else
- MoveCursorTo(event.location(), event.IsShiftDown());
- break;
- case 1:
- SelectWordAt(event.location());
- double_click_word_ = GetRenderText()->selection();
- break;
- case 2:
- SelectAll(false);
- break;
- default:
- NOTREACHED();
- }
- OnAfterUserAction();
- }
+ bool handled = controller_ && controller_->HandleMouseEvent(this, event);
+ if (!handled &&
+ (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton())) {
+ RequestFocus();
+ ShowImeIfNeeded();
+ }
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- if (event.IsOnlyMiddleMouseButton()) {
- if (GetRenderText()->IsPointInSelection(event.location())) {
- OnBeforeUserAction();
- ClearSelection();
- ui::ScopedClipboardWriter(
- ui::CLIPBOARD_TYPE_SELECTION).WriteText(base::string16());
- OnAfterUserAction();
- } else if (!read_only()) {
- PasteSelectionClipboard(event);
- }
- }
+ if (!handled && !HasFocus() && event.IsOnlyMiddleMouseButton())
+ RequestFocus();
#endif
- }
- return true;
+ return selection_controller_.OnMousePressed(event, handled);
}
bool Textfield::OnMouseDragged(const ui::MouseEvent& event) {
- last_drag_location_ = event.location();
-
- // Don't adjust the cursor on a potential drag and drop.
- if (initiating_drag_ || !event.IsOnlyLeftMouseButton())
- return true;
-
- // A timer is used to continuously scroll while selecting beyond side edges.
- const int x = event.location().x();
- if ((x >= 0 && x <= width()) || GetDragSelectionDelay() == 0) {
- drag_selection_timer_.Stop();
- SelectThroughLastDragLocation();
- } else if (!drag_selection_timer_.IsRunning()) {
- // Select through the edge of the visible text, then start the scroll timer.
- last_drag_location_.set_x(std::min(std::max(0, x), width()));
- SelectThroughLastDragLocation();
- drag_selection_timer_.Start(
- FROM_HERE, base::TimeDelta::FromMilliseconds(GetDragSelectionDelay()),
- this, &Textfield::SelectThroughLastDragLocation);
- }
-
- return true;
+ return selection_controller_.OnMouseDragged(event);
}
void Textfield::OnMouseReleased(const ui::MouseEvent& event) {
- OnBeforeUserAction();
- drag_selection_timer_.Stop();
- // Cancel suspected drag initiations, the user was clicking in the selection.
- if (initiating_drag_)
- MoveCursorTo(event.location(), false);
- initiating_drag_ = false;
- UpdateSelectionClipboard();
- OnAfterUserAction();
+ selection_controller_.OnMouseReleased(event);
+}
+
+void Textfield::OnMouseCaptureLost() {
+ selection_controller_.OnMouseCaptureLost();
}
WordLookupClient* Textfield::GetWordLookupClient() {
@@ -1136,6 +1068,13 @@ bool Textfield::GetDecoratedWordAtPoint(const gfx::Point& point,
}
////////////////////////////////////////////////////////////////////////////////
+// Textfield, SelectionControllerDelegate overrides:
+
+bool Textfield::HasTextBeingDragged() const {
+ return initiating_drag_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
// Textfield, ui::TouchEditable overrides:
void Textfield::SelectRect(const gfx::Point& start, const gfx::Point& end) {
@@ -1601,6 +1540,10 @@ gfx::RenderText* Textfield::GetRenderText() const {
return model_->render_text();
}
+gfx::Point Textfield::GetLastClickLocation() const {
+ return selection_controller_.last_click_location();
+}
+
base::string16 Textfield::GetSelectionClipboardText() const {
base::string16 selection_clipboard_text;
ui::Clipboard::GetForCurrentThread()->ReadText(
@@ -1799,7 +1742,7 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
}
cursor_changed |= GetSelectionModel() != selection_model;
- if (cursor_changed)
+ if (cursor_changed && HasSelection())
UpdateSelectionClipboard();
UpdateAfterChange(text_changed, cursor_changed);
OnAfterUserAction();
@@ -1808,6 +1751,79 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
////////////////////////////////////////////////////////////////////////////////
// Textfield, private:
+////////////////////////////////////////////////////////////////////////////////
+// Textfield, SelectionControllerDelegate overrides:
+
+gfx::RenderText* Textfield::GetRenderTextForSelectionController() {
+ return GetRenderText();
+}
+
+bool Textfield::IsReadOnly() const {
+ return read_only();
+}
+
+void Textfield::SetTextBeingDragged(bool value) {
+ initiating_drag_ = value;
+}
+
+int Textfield::GetViewHeight() const {
+ return height();
+}
+
+int Textfield::GetViewWidth() const {
+ return width();
+}
+
+int Textfield::GetDragSelectionDelay() const {
+ switch (ui::ScopedAnimationDurationScaleMode::duration_scale_mode()) {
+ case ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION:
+ return 100;
+ case ui::ScopedAnimationDurationScaleMode::FAST_DURATION:
+ return 25;
+ case ui::ScopedAnimationDurationScaleMode::SLOW_DURATION:
+ return 400;
+ case ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION:
+ return 1;
+ case ui::ScopedAnimationDurationScaleMode::ZERO_DURATION:
+ return 0;
+ }
+ return 100;
+}
+
+void Textfield::OnBeforePointerAction() {
+ OnBeforeUserAction();
+ if (model_->HasCompositionText())
+ model_->ConfirmCompositionText();
+}
+
+void Textfield::OnAfterPointerAction(bool text_changed,
+ bool selection_changed) {
+ OnAfterUserAction();
+ UpdateAfterChange(text_changed, selection_changed);
+}
+
+bool Textfield::PasteSelectionClipboard() {
+ DCHECK(performing_user_action_);
+ DCHECK(!read_only());
+ const base::string16 selection_clipboard_text = GetSelectionClipboardText();
+ if (selection_clipboard_text.empty())
+ return false;
+
+ model_->InsertText(selection_clipboard_text);
+ return true;
+}
+
+void Textfield::UpdateSelectionClipboard() {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ if (text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD) {
+ ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_SELECTION)
+ .WriteText(GetSelectedText());
+ if (controller_)
+ controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_SELECTION);
+ }
+#endif
+}
+
void Textfield::AccessibilitySetValue(const base::string16& new_value) {
if (!read_only()) {
SetText(new_value);
@@ -1898,39 +1914,6 @@ void Textfield::MoveCursorTo(const gfx::Point& point, bool select) {
UpdateAfterChange(false, true);
}
-void Textfield::SelectThroughLastDragLocation() {
- OnBeforeUserAction();
-
- const bool drags_to_end = PlatformStyle::kTextfieldDragVerticallyDragsToEnd;
- if (drags_to_end && last_drag_location_.y() < 0) {
- model_->MoveCursor(gfx::BreakType::LINE_BREAK,
- gfx::VisualCursorDirection::CURSOR_LEFT,
- gfx::SELECTION_RETAIN);
- } else if (drags_to_end && last_drag_location_.y() > height()) {
- model_->MoveCursor(gfx::BreakType::LINE_BREAK,
- gfx::VisualCursorDirection::CURSOR_RIGHT,
- gfx::SELECTION_RETAIN);
- } else {
- model_->MoveCursorTo(last_drag_location_, true);
- }
-
- if (aggregated_clicks_ == 1) {
- model_->SelectWord();
- // Expand the selection so the initially selected word remains selected.
- gfx::Range selection = GetRenderText()->selection();
- const size_t min = std::min(selection.GetMin(),
- double_click_word_.GetMin());
- const size_t max = std::max(selection.GetMax(),
- double_click_word_.GetMax());
- const bool reversed = selection.is_reversed();
- selection.set_start(reversed ? max : min);
- selection.set_end(reversed ? min : max);
- model_->SelectRange(selection);
- }
- UpdateAfterChange(false, true);
- OnAfterUserAction();
-}
-
void Textfield::OnCaretBoundsChanged() {
if (GetInputMethod())
GetInputMethod()->OnCaretBoundsChanged(this);
@@ -2004,24 +1987,6 @@ void Textfield::UpdateContextMenu() {
MenuRunner::ASYNC));
}
-void Textfield::TrackMouseClicks(const ui::MouseEvent& event) {
- if (event.IsOnlyLeftMouseButton()) {
- base::TimeDelta time_delta = event.time_stamp() - last_click_time_;
- if (!last_click_time_.is_null() &&
- time_delta.InMilliseconds() <= GetDoubleClickInterval() &&
- !ExceededDragThreshold(event.location() - last_click_location_)) {
- // Upon clicking after a triple click, the count should go back to double
- // click and alternate between double and triple. This assignment maps
- // 0 to 1, 1 to 2, 2 to 1.
- aggregated_clicks_ = (aggregated_clicks_ % 2) + 1;
- } else {
- aggregated_clicks_ = 0;
- }
- last_click_time_ = event.time_stamp();
- last_click_location_ = event.location();
- }
-}
-
bool Textfield::ImeEditingAllowed() const {
// Disallow input method editing of password fields.
ui::TextInputType t = GetTextInputType();
@@ -2051,35 +2016,6 @@ void Textfield::CreateTouchSelectionControllerAndNotifyIt() {
touch_selection_controller_->SelectionChanged();
}
-void Textfield::UpdateSelectionClipboard() const {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- if (performing_user_action_ && HasSelection() &&
- text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD) {
- ui::ScopedClipboardWriter(
- ui::CLIPBOARD_TYPE_SELECTION).WriteText(GetSelectedText());
- if (controller_)
- controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_SELECTION);
- }
-#endif
-}
-
-void Textfield::PasteSelectionClipboard(const ui::MouseEvent& event) {
- DCHECK(event.IsOnlyMiddleMouseButton());
- DCHECK(!read_only());
- base::string16 selection_clipboard_text = GetSelectionClipboardText();
- OnBeforeUserAction();
- const gfx::SelectionModel mouse =
- GetRenderText()->FindCursorPosition(event.location());
- if (!HasFocus())
- RequestFocus();
- model_->MoveCursorTo(mouse);
- if (!selection_clipboard_text.empty()) {
- model_->InsertText(selection_clipboard_text);
- UpdateAfterChange(true, true);
- }
- OnAfterUserAction();
-}
-
void Textfield::OnEditFailed() {
PlatformStyle::OnTextfieldEditFailed();
}

Powered by Google App Engine
This is Rietveld 408576698