Commit fc58b3e7 authored by Peter Kasting's avatar Peter Kasting Committed by Commit Bot

Simplify/clarify Textfield APIs.

In addition to avoiding multiple versions of the same-named function,
this is shorter and generally less-overlapping without loss of
functionality.

Bug: none
Change-Id: Ic7252c960d3ca18ea78351ea3386993e9eae91bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2363716Reviewed-by: default avatarmanuk hovanesian <manukh@chromium.org>
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Auto-Submit: Peter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#801074}
parent 3fce1e3f
...@@ -884,16 +884,14 @@ void OmniboxViewViews::SetTextAndSelectedRanges( ...@@ -884,16 +884,14 @@ void OmniboxViewViews::SetTextAndSelectedRanges(
static const uint32_t kPadTrailing = 30; static const uint32_t kPadTrailing = 30;
static const uint32_t kPadLeading = 10; static const uint32_t kPadLeading = 10;
// We use SetTextAndScrollAndSelectRange instead of SetText and // We use SetTextWithoutCaretBoundsChangeNotification() in order to avoid
// SetSelectedRange in order to avoid triggering accessibility events multiple // triggering accessibility events multiple times.
// times. SetTextWithoutCaretBoundsChangeNotification(text, ranges[0].end());
SetTextAndScrollAndSelectRange( Scroll({0, std::min<size_t>(ranges[0].end() + kPadTrailing, text.size()),
text, ranges[0].end(), ranges[0].end() - std::min(kPadLeading, ranges[0].end())});
{0, std::min<size_t>(ranges[0].end() + kPadTrailing, text.size()), // Setting the primary selected range will also fire an appropriate final
ranges[0].end() - std::min(kPadLeading, ranges[0].end())}, // accessibility event after the changes above.
ranges[0]); SetSelectedRanges(ranges);
for (size_t i = 1; i < ranges.size(); i++)
SetSelectedRange(ranges[i], false);
// Clear the additional text. // Clear the additional text.
SetAdditionalText(base::string16()); SetAdditionalText(base::string16());
...@@ -907,7 +905,7 @@ void OmniboxViewViews::SetSelectedRanges( ...@@ -907,7 +905,7 @@ void OmniboxViewViews::SetSelectedRanges(
SetSelectedRange(ranges[0]); SetSelectedRange(ranges[0]);
for (size_t i = 1; i < ranges.size(); i++) for (size_t i = 1; i < ranges.size(); i++)
SetSelectedRange(ranges[i], false); AddSecondarySelectedRange(ranges[i]);
} }
base::string16 OmniboxViewViews::GetSelectedText() const { base::string16 OmniboxViewViews::GetSelectedText() const {
......
This diff is collapsed.
...@@ -113,31 +113,28 @@ class VIEWS_EXPORT Textfield : public View, ...@@ -113,31 +113,28 @@ class VIEWS_EXPORT Textfield : public View,
// textfield. // textfield.
const base::string16& GetText() const; const base::string16& GetText() const;
// Sets the text currently displayed in the Textfield and the cursor position. // Sets the text currently displayed in the Textfield.
// Calls to |SetText| are often followed by updating the selection or cursor,
// which does not update the edit history. I.e. the cursor position after
// redoing this change will be determined by |cursor_position| here and not by
// any subsequent calls to e.g. |SetSelectedRange|. Selections are not
// explicitly set here since redo's clear the selection anyways.
void SetText(const base::string16& new_text); void SetText(const base::string16& new_text);
void SetText(const base::string16& new_text, size_t cursor_position);
// Sets the text currently displayed in the Textfield and the cursor position.
// Similar to calling SetText followed by SetSelectedRange calls, but will // Does not fire notifications about the caret bounds changing. This is
// dedupe some calls. Notably, this prevents OnCaretBoundsChanged from being // intended for low-level use, where callers need precise control over what
// called multiple times for a single change which can cause issues for // notifications are fired when, e.g. to avoid firing duplicate accessibility
// accessibility tools. // notifications, which can cause issues for accessibility tools. Updating the
// - |text| and |cursor_position| see SetText() comment above. // selection or cursor separately afterwards does not update the edit history,
// - |scroll_positions| a vector of positions to scroll into view. This can // i.e. the cursor position after redoing this change will be determined by
// contain multiple positions which can be useful to e.g. ensure multiple // |cursor_position| and not by subsequent calls to e.g. SetSelectedRange().
// positions are in view (if possible). Scrolls are applied in the order of void SetTextWithoutCaretBoundsChangeNotification(const base::string16& text,
// |scroll_positions|; i.e., later positions will have priority over earlier size_t cursor_position);
// positions.
// - |range| is used to invoke SetSelectedRange and will also be scrolled to. // Scrolls all of |scroll_positions| into view, if possible. For each
void SetTextAndScrollAndSelectRange( // position, the minimum scrolling change necessary to just bring the position
const base::string16& text, // into view is applied. |scroll_positions| are applied in order, so later
const size_t cursor_position, // positions will have priority over earlier positions if not all can be
const std::vector<size_t>& scroll_positions, // visible simultaneously.
const gfx::Range range); // NOTE: Unlike MoveCursorTo(), this will not fire any accessibility
// notifications.
void Scroll(const std::vector<size_t>& scroll_positions);
// Appends the given string to the previously-existing text in the field. // Appends the given string to the previously-existing text in the field.
void AppendText(const base::string16& new_text); void AppendText(const base::string16& new_text);
...@@ -235,7 +232,12 @@ class VIEWS_EXPORT Textfield : public View, ...@@ -235,7 +232,12 @@ class VIEWS_EXPORT Textfield : public View,
// Selects the specified logical text range. // Selects the specified logical text range.
void SetSelectedRange(const gfx::Range& range); void SetSelectedRange(const gfx::Range& range);
void SetSelectedRange(const gfx::Range& range, bool primary);
// Without clearing the current selected range, adds |range| as an additional
// selection.
// NOTE: Unlike SetSelectedRange(), this will not fire any accessibility
// notifications.
void AddSecondarySelectedRange(const gfx::Range& range);
// Gets the text selection model. // Gets the text selection model.
const gfx::SelectionModel& GetSelectionModel() const; const gfx::SelectionModel& GetSelectionModel() const;
...@@ -469,6 +471,8 @@ class VIEWS_EXPORT Textfield : public View, ...@@ -469,6 +471,8 @@ class VIEWS_EXPORT Textfield : public View,
private: private:
friend class TextfieldTestApi; friend class TextfieldTestApi;
enum class TextChangeType { kNone, kInternal, kUserTriggered };
// View overrides: // View overrides:
// Declared final since overriding by subclasses would interfere with the // Declared final since overriding by subclasses would interfere with the
// accounting related to the scheduled text edit command. Subclasses should // accounting related to the scheduled text edit command. Subclasses should
...@@ -504,7 +508,12 @@ class VIEWS_EXPORT Textfield : public View, ...@@ -504,7 +508,12 @@ class VIEWS_EXPORT Textfield : public View,
void UpdateSelectionBackgroundColor(); void UpdateSelectionBackgroundColor();
// Does necessary updates when the text and/or cursor position changes. // Does necessary updates when the text and/or cursor position changes.
void UpdateAfterChange(bool text_changed, bool cursor_changed); // If |notify_caret_bounds_changed| is not explicitly set, it will be computed
// based on whether either of the other arguments is set.
void UpdateAfterChange(
TextChangeType text_change_type,
bool cursor_changed,
base::Optional<bool> notify_caret_bounds_changed = base::nullopt);
// Updates cursor visibility and blinks the cursor if needed. // Updates cursor visibility and blinks the cursor if needed.
void ShowCursor(); void ShowCursor();
......
...@@ -845,98 +845,91 @@ TEST_F(TextfieldTest, ModelChangesTest) { ...@@ -845,98 +845,91 @@ TEST_F(TextfieldTest, ModelChangesTest) {
EXPECT_STR_EQ("this is a test", textfield_->GetSelectedText()); EXPECT_STR_EQ("this is a test", textfield_->GetSelectedText());
EXPECT_TRUE(last_contents_.empty()); EXPECT_TRUE(last_contents_.empty());
textfield_->SetTextAndScrollAndSelectRange(ASCIIToUTF16("another test"), 3, textfield_->SetTextWithoutCaretBoundsChangeNotification(
{}, {4, 5}); ASCIIToUTF16("another test"), 3);
EXPECT_STR_EQ("another test", model_->text()); EXPECT_STR_EQ("another test", model_->text());
EXPECT_STR_EQ("another test", textfield_->GetText()); EXPECT_STR_EQ("another test", textfield_->GetText());
EXPECT_STR_EQ("h", textfield_->GetSelectedText()); EXPECT_EQ(textfield_->GetCursorPosition(), 3u);
EXPECT_TRUE(last_contents_.empty()); EXPECT_TRUE(last_contents_.empty());
} }
TEST_F(TextfieldTest, SetTextAndScrollAndSelectRange_Scrolling) { TEST_F(TextfieldTest, Scroll) {
InitTextfield(); InitTextfield();
// Size the textfield wide enough to hold 10 characters. // Size the textfield wide enough to hold 10 characters.
gfx::test::RenderTextTestApi render_text_test_api(test_api_->GetRenderText()); gfx::test::RenderTextTestApi render_text_test_api(test_api_->GetRenderText());
render_text_test_api.SetGlyphWidth(10); constexpr int kGlyphWidth = 10;
// 10px/char * 10chars + 1px for cursor width render_text_test_api.SetGlyphWidth(kGlyphWidth);
test_api_->GetRenderText()->SetDisplayRect(gfx::Rect(0, 0, 101, 20)); constexpr int kCursorWidth = 1;
test_api_->GetRenderText()->SetDisplayRect(
// Should scroll cursor into view. gfx::Rect(0, 0, kGlyphWidth * 10 + kCursorWidth, 20));
textfield_->SetTextWithoutCaretBoundsChangeNotification(
ASCIIToUTF16("0123456789_123456789_123456789"), 0);
test_api_->SetDisplayOffsetX(0); test_api_->SetDisplayOffsetX(0);
textfield_->SetTextAndScrollAndSelectRange(
ASCIIToUTF16("0123456789_123456789_123456789"), 0, {}, {0, 20}); // Empty Scroll() call should have no effect.
textfield_->Scroll({});
EXPECT_EQ(test_api_->GetDisplayOffsetX(), 0);
// Selected range should scroll cursor into view.
textfield_->SetSelectedRange({0, 20});
EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100); EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100);
EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(0, 20));
// Cursor position should not affect scroll. // Selected range should override new cursor position.
test_api_->SetDisplayOffsetX(0); test_api_->SetDisplayOffsetX(0);
textfield_->SetTextAndScrollAndSelectRange( textfield_->SetTextWithoutCaretBoundsChangeNotification(
ASCIIToUTF16("0123456789_123456789_123456789"), 30, {}, {20, 20}); ASCIIToUTF16("0123456789_123456789_123456789"), 30);
EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100); EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100);
EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(20));
// Scroll positions should affect scroll. // Scroll positions should affect scroll.
textfield_->SetSelectedRange(gfx::Range());
test_api_->SetDisplayOffsetX(0); test_api_->SetDisplayOffsetX(0);
textfield_->SetTextAndScrollAndSelectRange( textfield_->Scroll({30});
ASCIIToUTF16("0123456789_123456789_123456789"), 0, {30}, {20, 20});
EXPECT_EQ(test_api_->GetDisplayOffsetX(), -200); EXPECT_EQ(test_api_->GetDisplayOffsetX(), -200);
EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(20));
// Should scroll no more than necessary; e.g., scrolling right should put the // Should scroll right no more than necessary.
// cursor at the right edge.
test_api_->SetDisplayOffsetX(0); test_api_->SetDisplayOffsetX(0);
textfield_->SetTextAndScrollAndSelectRange( textfield_->Scroll({15});
ASCIIToUTF16("0123456789_123456789_123456789"), 0, {}, {15, 15});
EXPECT_EQ(test_api_->GetDisplayOffsetX(), -50); EXPECT_EQ(test_api_->GetDisplayOffsetX(), -50);
EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(15));
// Should scroll no more than necessary; e.g., scrolling left should put the // Should scroll left no more than necessary.
// cursor at the left edge.
test_api_->SetDisplayOffsetX(-200); // Scroll all the way right. test_api_->SetDisplayOffsetX(-200); // Scroll all the way right.
textfield_->SetTextAndScrollAndSelectRange( textfield_->Scroll({15});
ASCIIToUTF16("0123456789_123456789_123456789"), 0, {}, {15, 15});
EXPECT_EQ(test_api_->GetDisplayOffsetX(), -150); EXPECT_EQ(test_api_->GetDisplayOffsetX(), -150);
EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(15));
// Should scroll no more than necessary; e.g., scrolling to a position already // Should not scroll if position is already in view.
// in view should not change the offset.
test_api_->SetDisplayOffsetX(-100); // Scroll the middle 10 chars into view. test_api_->SetDisplayOffsetX(-100); // Scroll the middle 10 chars into view.
textfield_->SetTextAndScrollAndSelectRange( textfield_->Scroll({15});
ASCIIToUTF16("0123456789_123456789_123456789"), 0, {}, {15, 15});
EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100); EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100);
EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(15));
// With multiple scroll positions, the Last scroll position should be scrolled // With multiple scroll positions, the Last scroll position takes priority.
// to after previous scroll positions.
test_api_->SetDisplayOffsetX(0); test_api_->SetDisplayOffsetX(0);
textfield_->SetTextAndScrollAndSelectRange( textfield_->Scroll({30, 0});
ASCIIToUTF16("0123456789_123456789_123456789"), 0, {30, 0}, {20, 20}); EXPECT_EQ(test_api_->GetDisplayOffsetX(), 0);
textfield_->Scroll({30, 0, 20});
EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100); EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100);
EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(20));
// With multiple scroll positions, the previous scroll positions should be // With multiple scroll positions, the previous scroll positions should be
// scrolled to anyways. // scrolled to anyways.
test_api_->SetDisplayOffsetX(0); test_api_->SetDisplayOffsetX(0);
textfield_->SetTextAndScrollAndSelectRange( textfield_->Scroll({30, 20});
ASCIIToUTF16("0123456789_123456789_123456789"), 0, {30, 20}, {20, 20});
EXPECT_EQ(test_api_->GetDisplayOffsetX(), -200); EXPECT_EQ(test_api_->GetDisplayOffsetX(), -200);
EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(20));
// With a non empty selection, only the selection end should affect scrolling. // Only the selection end should affect scrolling.
test_api_->SetDisplayOffsetX(0); test_api_->SetDisplayOffsetX(0);
textfield_->SetTextAndScrollAndSelectRange( textfield_->Scroll({20});
ASCIIToUTF16("0123456789_123456789_123456789"), 0, {0}, {30, 0}); textfield_->SetSelectedRange({30, 20});
EXPECT_EQ(test_api_->GetDisplayOffsetX(), 0); EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100);
EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(30, 0));
} }
TEST_F(TextfieldTest, SetTextAndScrollAndSelectRange_ModelEditHistory) { TEST_F(TextfieldTest,
SetTextWithoutCaretBoundsChangeNotification_ModelEditHistory) {
InitTextfield(); InitTextfield();
// The cursor and selected range should reflect the |range| parameter. // The cursor and selected range should reflect the selected range.
textfield_->SetTextAndScrollAndSelectRange( textfield_->SetTextWithoutCaretBoundsChangeNotification(
ASCIIToUTF16("0123456789_123456789_123456789"), 20, {}, {10, 15}); ASCIIToUTF16("0123456789_123456789_123456789"), 20);
textfield_->SetSelectedRange({10, 15});
EXPECT_EQ(textfield_->GetCursorPosition(), 15u); EXPECT_EQ(textfield_->GetCursorPosition(), 15u);
EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(10, 15)); EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(10, 15));
...@@ -1292,7 +1285,7 @@ TEST_F(TextfieldTest, ModifySelectionWithMultipleSelections) { ...@@ -1292,7 +1285,7 @@ TEST_F(TextfieldTest, ModifySelectionWithMultipleSelections) {
InitTextfield(); InitTextfield();
textfield_->SetText(ASCIIToUTF16("0123456 89")); textfield_->SetText(ASCIIToUTF16("0123456 89"));
textfield_->SetSelectedRange(gfx::Range(3, 5)); textfield_->SetSelectedRange(gfx::Range(3, 5));
textfield_->SetSelectedRange(gfx::Range(8, 9), false); textfield_->AddSecondarySelectedRange(gfx::Range(8, 9));
test_api_->ExecuteTextEditCommand( test_api_->ExecuteTextEditCommand(
ui::TextEditCommand::MOVE_RIGHT_AND_MODIFY_SELECTION); ui::TextEditCommand::MOVE_RIGHT_AND_MODIFY_SELECTION);
...@@ -1411,8 +1404,8 @@ TEST_F(TextfieldTest, DeletionWithMultipleSelections) { ...@@ -1411,8 +1404,8 @@ TEST_F(TextfieldTest, DeletionWithMultipleSelections) {
textfield_->SetText(ASCIIToUTF16("one two three")); textfield_->SetText(ASCIIToUTF16("one two three"));
// Select: o[ne] [two] th[re]e // Select: o[ne] [two] th[re]e
textfield_->SetSelectedRange(gfx::Range(4, 7)); textfield_->SetSelectedRange(gfx::Range(4, 7));
textfield_->SetSelectedRange(gfx::Range(10, 12), false); textfield_->AddSecondarySelectedRange(gfx::Range(10, 12));
textfield_->SetSelectedRange(gfx::Range(1, 3), false); textfield_->AddSecondarySelectedRange(gfx::Range(1, 3));
SendWordEvent(cases[i].key, cases[i].shift); SendWordEvent(cases[i].key, cases[i].shift);
EXPECT_STR_EQ("o the", textfield_->GetText()); EXPECT_STR_EQ("o the", textfield_->GetText());
EXPECT_EQ(gfx::Range(2), textfield_->GetSelectedRange()); EXPECT_EQ(gfx::Range(2), textfield_->GetSelectedRange());
...@@ -1709,14 +1702,14 @@ TEST_F(TextfieldTest, CursorMovementWithMultipleSelections) { ...@@ -1709,14 +1702,14 @@ TEST_F(TextfieldTest, CursorMovementWithMultipleSelections) {
textfield_->SetText(ASCIIToUTF16("012 456 890 234 678")); textfield_->SetText(ASCIIToUTF16("012 456 890 234 678"));
// [p] [s] // [p] [s]
textfield_->SetSelectedRange({4, 7}); textfield_->SetSelectedRange({4, 7});
textfield_->SetSelectedRange({12, 15}, false); textfield_->AddSecondarySelectedRange({12, 15});
test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_LEFT); test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_LEFT);
EXPECT_EQ(gfx::Range(4, 4), textfield_->GetSelectedRange()); EXPECT_EQ(gfx::Range(4, 4), textfield_->GetSelectedRange());
EXPECT_EQ(0U, textfield_->GetSelectionModel().secondary_selections().size()); EXPECT_EQ(0U, textfield_->GetSelectionModel().secondary_selections().size());
textfield_->SetSelectedRange({4, 7}); textfield_->SetSelectedRange({4, 7});
textfield_->SetSelectedRange({12, 15}, false); textfield_->AddSecondarySelectedRange({12, 15});
test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_RIGHT); test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_RIGHT);
EXPECT_EQ(gfx::Range(7, 7), textfield_->GetSelectedRange()); EXPECT_EQ(gfx::Range(7, 7), textfield_->GetSelectedRange());
...@@ -1730,13 +1723,13 @@ TEST_F(TextfieldTest, ShouldShowCursor) { ...@@ -1730,13 +1723,13 @@ TEST_F(TextfieldTest, ShouldShowCursor) {
// should show cursor when there's no primary selection // should show cursor when there's no primary selection
textfield_->SetSelectedRange({4, 4}); textfield_->SetSelectedRange({4, 4});
EXPECT_TRUE(test_api_->ShouldShowCursor()); EXPECT_TRUE(test_api_->ShouldShowCursor());
textfield_->SetSelectedRange({1, 3}, false); textfield_->AddSecondarySelectedRange({1, 3});
EXPECT_TRUE(test_api_->ShouldShowCursor()); EXPECT_TRUE(test_api_->ShouldShowCursor());
// should not show cursor when there's a primary selection // should not show cursor when there's a primary selection
textfield_->SetSelectedRange({4, 7}); textfield_->SetSelectedRange({4, 7});
EXPECT_FALSE(test_api_->ShouldShowCursor()); EXPECT_FALSE(test_api_->ShouldShowCursor());
textfield_->SetSelectedRange({1, 3}, false); textfield_->AddSecondarySelectedRange({1, 3});
EXPECT_FALSE(test_api_->ShouldShowCursor()); EXPECT_FALSE(test_api_->ShouldShowCursor());
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment