Commit 2e4bafe9 authored by kochi@chromium.org's avatar kochi@chromium.org

Implement STYLE_LOWERCASE style for Aura NativeTextfield.

BUG=109308
TEST=views_unittest --gtest_filter="NativeTextfieldViews*"


Review URL: http://codereview.chromium.org/9358049

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132525 0039d316-1c4b-4281-b951-d872f2087c98
parent 4ebce1e3
......@@ -229,14 +229,7 @@ views::Label* EditSearchEngineDialog::CreateLabel(int message_id) {
Textfield* EditSearchEngineDialog::CreateTextfield(const string16& text,
bool lowercase) {
Textfield* text_field = new Textfield(
#if defined(USE_AURA)
Textfield::STYLE_DEFAULT);
NOTIMPLEMENTED(); // TODO(beng): support lowercase mode in
// NativeTextfieldViews.
// http://crbug.com/109308
#else
lowercase ? Textfield::STYLE_LOWERCASE : Textfield::STYLE_DEFAULT);
#endif
text_field->SetText(text);
text_field->SetController(this);
return text_field;
......
......@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
......@@ -37,6 +38,7 @@
#include "ui/views/metrics.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
#include "unicode/uchar.h"
#if defined(USE_AURA)
#include "ui/base/cursor/cursor.h"
......@@ -77,9 +79,6 @@ NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
TouchSelectionController::create(this))) {
set_border(text_border_);
// Lowercase is not supported.
DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE);
#if defined(OS_CHROMEOS)
GetRenderText()->SetFontList(gfx::FontList(l10n_util::GetStringUTF8(
IDS_UI_FONT_FAMILY_CROS)));
......@@ -198,6 +197,7 @@ int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) {
GetRenderText()->FindCursorPosition(event.location());
string16 text;
event.data().GetString(&text);
text = GetTextForDisplay(text);
// We'll delete the current selection for a drag and drop within this view.
bool move = initiating_drag_ && !event.IsControlDown() &&
......@@ -321,7 +321,7 @@ string16 NativeTextfieldViews::GetText() const {
}
void NativeTextfieldViews::UpdateText() {
model_->SetText(textfield_->text());
model_->SetText(GetTextForDisplay(textfield_->text()));
OnCaretBoundsChanged();
SchedulePaint();
textfield_->GetWidget()->NotifyAccessibilityEvent(
......@@ -331,7 +331,7 @@ void NativeTextfieldViews::UpdateText() {
void NativeTextfieldViews::AppendText(const string16& text) {
if (text.empty())
return;
model_->Append(text);
model_->Append(GetTextForDisplay(text));
OnCaretBoundsChanged();
SchedulePaint();
}
......@@ -669,9 +669,9 @@ void NativeTextfieldViews::InsertText(const string16& text) {
OnBeforeUserAction();
skip_input_method_cancel_composition_ = true;
if (GetRenderText()->insert_mode())
model_->InsertText(text);
model_->InsertText(GetTextForDisplay(text));
else
model_->ReplaceText(text);
model_->ReplaceText(GetTextForDisplay(text));
skip_input_method_cancel_composition_ = false;
UpdateAfterChange(true, true);
OnAfterUserAction();
......@@ -690,6 +690,9 @@ void NativeTextfieldViews::InsertChar(char16 ch, int flags) {
else
model_->ReplaceChar(ch);
skip_input_method_cancel_composition_ = false;
model_->SetText(GetTextForDisplay(GetText()));
UpdateAfterChange(true, true);
OnAfterUserAction();
}
......@@ -792,6 +795,11 @@ gfx::RenderText* NativeTextfieldViews::GetRenderText() const {
return model_->render_text();
}
string16 NativeTextfieldViews::GetTextForDisplay(const string16& text) {
return textfield_->style() & Textfield::STYLE_LOWERCASE ?
base::i18n::ToLower(text) : text;
}
void NativeTextfieldViews::UpdateCursor() {
is_cursor_visible_ = !is_cursor_visible_;
RepaintCursor();
......@@ -1047,14 +1055,23 @@ bool NativeTextfieldViews::Copy() {
}
bool NativeTextfieldViews::Paste() {
const string16 original_text = GetText();
const bool success = model_->Paste();
// Calls TextfieldController::ContentsChanged() explicitly if the paste action
// did not change the content at all. See http://crbug.com/79002
if (success && GetText() == textfield_->text()) {
TextfieldController* controller = textfield_->GetController();
if (controller)
controller->ContentsChanged(textfield_, textfield_->text());
if (success) {
// As Paste is handled in model_->Paste(), the RenderText may contain
// upper case characters. This is not consistent with other places
// which keeps RenderText only containing lower case characters.
string16 new_text = GetTextForDisplay(GetText());
model_->SetText(new_text);
// Calls TextfieldController::ContentsChanged() explicitly if the paste
// action did not change the content at all. See http://crbug.com/79002
if (new_text == original_text) {
TextfieldController* controller = textfield_->GetController();
if (controller)
controller->ContentsChanged(textfield_, textfield_->text());
}
}
return success;
}
......
......@@ -172,6 +172,10 @@ class VIEWS_EXPORT NativeTextfieldViews : public TouchSelectionClientView,
// Returns the TextfieldViewsModel's text/cursor/selection rendering model.
gfx::RenderText* GetRenderText() const;
// Converts |text| according to textfield style, e.g. lower case if
// |textfield_| has STYLE_LOWERCASE style.
string16 GetTextForDisplay(const string16& text);
// A callback function to periodically update the cursor state.
void UpdateCursor();
......@@ -197,7 +201,7 @@ class VIEWS_EXPORT NativeTextfieldViews : public TouchSelectionClientView,
// changed.
void UpdateAfterChange(bool text_changed, bool cursor_changed);
// Utility function to prepare the context menu..
// Utility function to prepare the context menu.
void UpdateContextMenu();
// Convenience method to call InputMethod::OnTextInputTypeChanged();
......
......@@ -359,6 +359,84 @@ TEST_F(NativeTextfieldViewsTest, ModelChangesTest) {
EXPECT_TRUE(last_contents_.empty());
}
TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCase) {
// Check if |model_|'s text is properly lowercased for STYLE_LOWERCASE.
InitTextfield(Textfield::STYLE_LOWERCASE);
EXPECT_EQ(0U, textfield_->GetCursorPosition());
last_contents_.clear();
textfield_->SetText(ASCIIToUTF16("THIS IS"));
EXPECT_EQ(0U, textfield_->GetCursorPosition());
EXPECT_STR_EQ("this is", model_->GetText());
EXPECT_STR_EQ("THIS IS", textfield_->text());
EXPECT_TRUE(last_contents_.empty());
textfield_->AppendText(ASCIIToUTF16(" A TEST"));
EXPECT_EQ(0U, textfield_->GetCursorPosition());
EXPECT_STR_EQ("this is a test", model_->GetText());
EXPECT_STR_EQ("THIS IS A TEST", textfield_->text());
EXPECT_TRUE(last_contents_.empty());
}
TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseI18n) {
// Check if lower case conversion works for non-ASCII characters.
InitTextfield(Textfield::STYLE_LOWERCASE);
EXPECT_EQ(0U, textfield_->GetCursorPosition());
last_contents_.clear();
// Zenkaku Japanese "ABCabc"
textfield_->SetText(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"));
EXPECT_EQ(0U, textfield_->GetCursorPosition());
// Zenkaku Japanese "abcabc"
EXPECT_EQ(WideToUTF16(L"\xFF41\xFF42\xFF43\xFF41\xFF42\xFF43"),
model_->GetText());
// Zenkaku Japanese "ABCabc"
EXPECT_EQ(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"),
textfield_->text());
EXPECT_TRUE(last_contents_.empty());
// Zenkaku Japanese "XYZxyz"
textfield_->AppendText(WideToUTF16(L"\xFF38\xFF39\xFF3A\xFF58\xFF59\xFF5A"));
EXPECT_EQ(0U, textfield_->GetCursorPosition());
// Zenkaku Japanese "abcabcxyzxyz"
EXPECT_EQ(WideToUTF16(L"\xFF41\xFF42\xFF43\xFF41\xFF42\xFF43"
L"\xFF58\xFF59\xFF5A\xFF58\xFF59\xFF5A"),
model_->GetText());
// Zenkaku Japanese "ABCabcXYZxyz"
EXPECT_EQ(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"
L"\xFF38\xFF39\xFF3A\xFF58\xFF59\xFF5A"),
textfield_->text());
EXPECT_TRUE(last_contents_.empty());
}
TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseWithLocale) {
// Check if lower case conversion honors locale properly.
std::string locale = l10n_util::GetApplicationLocale("");
base::i18n::SetICUDefaultLocale("tr");
InitTextfield(Textfield::STYLE_LOWERCASE);
EXPECT_EQ(0U, textfield_->GetCursorPosition());
last_contents_.clear();
// Turkish 'I' should be converted to dotless 'i' (U+0131).
textfield_->SetText(WideToUTF16(L"I"));
EXPECT_EQ(0U, textfield_->GetCursorPosition());
EXPECT_EQ(WideToUTF16(L"\x0131"), model_->GetText());
EXPECT_EQ(WideToUTF16(L"I"), textfield_->text());
EXPECT_TRUE(last_contents_.empty());
base::i18n::SetICUDefaultLocale(locale);
// On default (en) locale, 'I' should be converted to 'i'.
textfield_->SetText(WideToUTF16(L"I"));
EXPECT_EQ(0U, textfield_->GetCursorPosition());
EXPECT_EQ(WideToUTF16(L"i"), model_->GetText());
EXPECT_EQ(WideToUTF16(L"I"), textfield_->text());
EXPECT_TRUE(last_contents_.empty());
}
TEST_F(NativeTextfieldViewsTest, KeyTest) {
InitTextfield(Textfield::STYLE_DEFAULT);
SendKeyEvent(ui::VKEY_C, true, false);
......
......@@ -185,7 +185,7 @@ class VIEWS_EXPORT TextfieldViewsModel {
bool Copy();
// Pastes text from the clipboard at current cursor position. Returns true
// if text has changed after pasting.
// if any text is pasted.
bool Paste();
// Tells if any text is selected, even if the selection is in composition
......@@ -208,7 +208,7 @@ class VIEWS_EXPORT TextfieldViewsModel {
void GetTextRange(ui::Range* range) const;
// Sets composition text and attributes. If there is composition text already,
// itll be replaced by the new one. Otherwise, current selection will be
// it'll be replaced by the new one. Otherwise, current selection will be
// replaced. If there is no selection, the composition text will be inserted
// at the insertion point.
// Any changes to the model except text insertion will confirm the current
......
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