Commit 22f3dbdc authored by oshima@google.com's avatar oshima@google.com

Make uneditable when readonly.

 This change makes the textfield uneditable. The text can
still be updated via API (which is necessary to show URL
in popup).

BUG=none
TEST=uadded new ReadOnlyTest

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72022 0039d316-1c4b-4281-b951-d872f2087c98
parent 777389e5
...@@ -329,18 +329,19 @@ bool NativeTextfieldViews::IsCommandIdChecked(int command_id) const { ...@@ -329,18 +329,19 @@ bool NativeTextfieldViews::IsCommandIdChecked(int command_id) const {
} }
bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const { bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const {
bool editable = !textfield_->read_only();
string16 result; string16 result;
switch (command_id) { switch (command_id) {
case IDS_APP_CUT: case IDS_APP_CUT:
return model_->HasSelection(); return editable && model_->HasSelection();
case IDS_APP_COPY: case IDS_APP_COPY:
return model_->HasSelection(); return model_->HasSelection();
case IDS_APP_PASTE: case IDS_APP_PASTE:
views::ViewsDelegate::views_delegate->GetClipboard() views::ViewsDelegate::views_delegate->GetClipboard()
->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); ->ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
return !result.empty(); return editable && !result.empty();
case IDS_APP_DELETE: case IDS_APP_DELETE:
return model_->HasSelection(); return editable && model_->HasSelection();
case IDS_APP_SELECT_ALL: case IDS_APP_SELECT_ALL:
return true; return true;
default: default:
...@@ -356,18 +357,22 @@ bool NativeTextfieldViews::GetAcceleratorForCommandId(int command_id, ...@@ -356,18 +357,22 @@ bool NativeTextfieldViews::GetAcceleratorForCommandId(int command_id,
void NativeTextfieldViews::ExecuteCommand(int command_id) { void NativeTextfieldViews::ExecuteCommand(int command_id) {
bool text_changed = false; bool text_changed = false;
bool editable = !textfield_->read_only();
switch (command_id) { switch (command_id) {
case IDS_APP_CUT: case IDS_APP_CUT:
text_changed = model_->Cut(); if (editable)
text_changed = model_->Cut();
break; break;
case IDS_APP_COPY: case IDS_APP_COPY:
model_->Copy(); model_->Copy();
break; break;
case IDS_APP_PASTE: case IDS_APP_PASTE:
text_changed = model_->Paste(); if (editable)
text_changed = model_->Paste();
break; break;
case IDS_APP_DELETE: case IDS_APP_DELETE:
text_changed = model_->Delete(); if (editable)
text_changed = model_->Delete();
break; break;
case IDS_APP_SELECT_ALL: case IDS_APP_SELECT_ALL:
SelectAll(); SelectAll();
...@@ -519,6 +524,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { ...@@ -519,6 +524,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
// TODO(oshima): shift-tab does not work. Figure out why and fix. // TODO(oshima): shift-tab does not work. Figure out why and fix.
if (key_code == ui::VKEY_TAB) if (key_code == ui::VKEY_TAB)
return false; return false;
bool editable = !textfield_->read_only();
bool selection = key_event.IsShiftDown(); bool selection = key_event.IsShiftDown();
bool control = key_event.IsControlDown(); bool control = key_event.IsControlDown();
bool text_changed = false; bool text_changed = false;
...@@ -531,7 +537,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { ...@@ -531,7 +537,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
} }
break; break;
case ui::VKEY_X: case ui::VKEY_X:
if (control) if (control && editable)
text_changed = model_->Cut(); text_changed = model_->Cut();
break; break;
case ui::VKEY_C: case ui::VKEY_C:
...@@ -539,7 +545,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { ...@@ -539,7 +545,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
model_->Copy(); model_->Copy();
break; break;
case ui::VKEY_V: case ui::VKEY_V:
if (control) if (control && editable)
text_changed = model_->Paste(); text_changed = model_->Paste();
break; break;
case ui::VKEY_RIGHT: case ui::VKEY_RIGHT:
...@@ -561,6 +567,8 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { ...@@ -561,6 +567,8 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
cursor_changed = true; cursor_changed = true;
break; break;
case ui::VKEY_BACK: case ui::VKEY_BACK:
if (!editable)
break;
if (!model_->HasSelection()) { if (!model_->HasSelection()) {
if (selection && control) { if (selection && control) {
// If both shift and control are pressed, then erase upto the // If both shift and control are pressed, then erase upto the
...@@ -579,6 +587,8 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { ...@@ -579,6 +587,8 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
cursor_changed = true; cursor_changed = true;
break; break;
case ui::VKEY_DELETE: case ui::VKEY_DELETE:
if (!editable)
break;
if (!model_->HasSelection()) { if (!model_->HasSelection()) {
if (selection && control) { if (selection && control) {
// If both shift and control are pressed, then erase upto the // If both shift and control are pressed, then erase upto the
...@@ -603,7 +613,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { ...@@ -603,7 +613,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
break; break;
} }
char16 print_char = GetPrintableChar(key_event); char16 print_char = GetPrintableChar(key_event);
if (!control && print_char) { if (!control && print_char && editable) {
if (insert_) if (insert_)
model_->Insert(print_char); model_->Insert(print_char);
else else
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/keycodes/keyboard_codes.h" #include "ui/base/keycodes/keyboard_codes.h"
#include "views/controls/menu/menu_2.h" #include "views/controls/menu/menu_2.h"
#include "views/controls/textfield/native_textfield_views.h" #include "views/controls/textfield/native_textfield_views.h"
...@@ -21,8 +22,12 @@ ...@@ -21,8 +22,12 @@
namespace views { namespace views {
// Convert to Wide so that the printed string will be readable when
// check fails.
#define EXPECT_STR_EQ(ascii, utf16) \ #define EXPECT_STR_EQ(ascii, utf16) \
EXPECT_EQ(ASCIIToWide(ascii), UTF16ToWide(utf16)) EXPECT_EQ(ASCIIToWide(ascii), UTF16ToWide(utf16))
#define EXPECT_STR_NE(ascii, utf16) \
EXPECT_NE(ASCIIToWide(ascii), UTF16ToWide(utf16))
// TODO(oshima): Move tests that are independent of TextfieldViews to // TODO(oshima): Move tests that are independent of TextfieldViews to
// textfield_unittests.cc once we move the test utility functions // textfield_unittests.cc once we move the test utility functions
...@@ -404,8 +409,8 @@ void VerifyTextfieldContextMenuContents(bool textfield_has_selection, ...@@ -404,8 +409,8 @@ void VerifyTextfieldContextMenuContents(bool textfield_has_selection,
EXPECT_EQ(textfield_has_selection, menu_model->IsEnabledAt(1 /* COPY */)); EXPECT_EQ(textfield_has_selection, menu_model->IsEnabledAt(1 /* COPY */));
EXPECT_EQ(textfield_has_selection, menu_model->IsEnabledAt(3 /* DELETE */)); EXPECT_EQ(textfield_has_selection, menu_model->IsEnabledAt(3 /* DELETE */));
string16 str; string16 str;
views::ViewsDelegate::views_delegate->GetClipboard() views::ViewsDelegate::views_delegate->GetClipboard()->
->ReadText(ui::Clipboard::BUFFER_STANDARD, &str); ReadText(ui::Clipboard::BUFFER_STANDARD, &str);
EXPECT_NE(str.empty(), menu_model->IsEnabledAt(2 /* PASTE */)); EXPECT_NE(str.empty(), menu_model->IsEnabledAt(2 /* PASTE */));
} }
...@@ -423,4 +428,65 @@ TEST_F(NativeTextfieldViewsTest, ContextMenuDisplayTest) { ...@@ -423,4 +428,65 @@ TEST_F(NativeTextfieldViewsTest, ContextMenuDisplayTest) {
VerifyTextfieldContextMenuContents(true, GetContextMenu()->model()); VerifyTextfieldContextMenuContents(true, GetContextMenu()->model());
} }
TEST_F(NativeTextfieldViewsTest, ReadOnlyTest) {
scoped_ptr<TestViewsDelegate> test_views_delegate(new TestViewsDelegate());
AutoReset<views::ViewsDelegate*> auto_reset(
&views::ViewsDelegate::views_delegate, test_views_delegate.get());
InitTextfield(Textfield::STYLE_DEFAULT);
textfield_->SetText(ASCIIToUTF16(" one two three "));
textfield_->SetReadOnly(true);
SendKeyEventToTextfieldViews(ui::VKEY_HOME);
EXPECT_EQ(0U, textfield_->GetCursorPosition());
SendKeyEventToTextfieldViews(ui::VKEY_END);
EXPECT_EQ(15U, textfield_->GetCursorPosition());
SendKeyEventToTextfieldViews(ui::VKEY_LEFT, false, false);
EXPECT_EQ(14U, textfield_->GetCursorPosition());
SendKeyEventToTextfieldViews(ui::VKEY_LEFT, false, true);
EXPECT_EQ(9U, textfield_->GetCursorPosition());
SendKeyEventToTextfieldViews(ui::VKEY_LEFT, true, true);
EXPECT_EQ(5U, textfield_->GetCursorPosition());
EXPECT_STR_EQ("two ", textfield_->GetSelectedText());
textfield_->SelectAll();
EXPECT_STR_EQ(" one two three ", textfield_->GetSelectedText());
// CUT&PASTE does not work, but COPY works
SendKeyEventToTextfieldViews(ui::VKEY_X, false, true);
EXPECT_STR_EQ(" one two three ", textfield_->GetSelectedText());
string16 str;
views::ViewsDelegate::views_delegate->GetClipboard()->
ReadText(ui::Clipboard::BUFFER_STANDARD, &str);
EXPECT_STR_NE(" one two three ", str);
SendKeyEventToTextfieldViews(ui::VKEY_C, false, true);
views::ViewsDelegate::views_delegate->GetClipboard()->
ReadText(ui::Clipboard::BUFFER_STANDARD, &str);
EXPECT_STR_EQ(" one two three ", str);
// SetText should work even in read only mode.
textfield_->SetText(ASCIIToUTF16(" four five six "));
EXPECT_STR_EQ(" four five six ", textfield_->text());
// Paste shouldn't work.
SendKeyEventToTextfieldViews(ui::VKEY_V, false, true);
EXPECT_STR_EQ(" four five six ", textfield_->text());
EXPECT_TRUE(textfield_->GetSelectedText().empty());
textfield_->SelectAll();
EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
// Text field is unmodifiable and selection shouldn't change.
SendKeyEventToTextfieldViews(ui::VKEY_DELETE);
EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
SendKeyEventToTextfieldViews(ui::VKEY_BACK);
EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
SendKeyEventToTextfieldViews(ui::VKEY_T);
EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText());
}
} // namespace views } // namespace views
...@@ -36,9 +36,11 @@ class NativeTextfieldWrapper; ...@@ -36,9 +36,11 @@ class NativeTextfieldWrapper;
// TextRange specifies the range of text in the Textfield. This is // TextRange specifies the range of text in the Textfield. This is
// used to specify selected text and will be used to change the // used to specify selected text and will be used to change the
// attributes of characters in the textfield. The range preserves the // attributes of characters in the textfield. When this is used for
// direction, and selecting from the end to the begining is considered // selection, the end is caret position, and the start is where
// "reverse" order. // selection started. The range preserves the direction, and
// selecting from the end to the begining is considered "reverse"
// order. (that is, start > end is reverse)
class TextRange { class TextRange {
public: public:
TextRange() : start_(0), end_(0) {} TextRange() : start_(0), end_(0) {}
......
...@@ -230,8 +230,9 @@ void TextfieldViewsModel::SelectRange(const TextRange& range) { ...@@ -230,8 +230,9 @@ void TextfieldViewsModel::SelectRange(const TextRange& range) {
} }
void TextfieldViewsModel::SelectAll() { void TextfieldViewsModel::SelectAll() {
cursor_pos_ = 0; // SelectAll selects towards the end.
selection_begin_ = text_.length(); cursor_pos_ = text_.length();
selection_begin_ = 0;
} }
void TextfieldViewsModel::ClearSelection() { void TextfieldViewsModel::ClearSelection() {
......
...@@ -104,6 +104,11 @@ TEST_F(TextfieldViewsModelTest, Selection) { ...@@ -104,6 +104,11 @@ TEST_F(TextfieldViewsModelTest, Selection) {
EXPECT_EQ(string16(), model.GetSelectedText()); EXPECT_EQ(string16(), model.GetSelectedText());
model.SelectAll(); model.SelectAll();
EXPECT_STR_EQ("HELLO", model.GetSelectedText()); EXPECT_STR_EQ("HELLO", model.GetSelectedText());
// SelectAll should select towards the end.
TextRange range;
model.GetSelectedRange(&range);
EXPECT_EQ(0U, range.start());
EXPECT_EQ(5U, range.end());
// Select and move cursor // Select and move cursor
model.MoveCursorTo(1U, false); model.MoveCursorTo(1U, false);
...@@ -168,7 +173,7 @@ TEST_F(TextfieldViewsModelTest, Password) { ...@@ -168,7 +173,7 @@ TEST_F(TextfieldViewsModelTest, Password) {
model.SelectAll(); model.SelectAll();
EXPECT_STR_EQ("ELLO", model.GetSelectedText()); EXPECT_STR_EQ("ELLO", model.GetSelectedText());
EXPECT_EQ(0U, model.cursor_pos()); EXPECT_EQ(4U, model.cursor_pos());
model.Insert('X'); model.Insert('X');
EXPECT_STR_EQ("*", model.GetVisibleText()); EXPECT_STR_EQ("*", model.GetVisibleText());
...@@ -288,10 +293,11 @@ TEST_F(TextfieldViewsModelTest, SetText) { ...@@ -288,10 +293,11 @@ TEST_F(TextfieldViewsModelTest, SetText) {
EXPECT_EQ(5U, model.cursor_pos()); EXPECT_EQ(5U, model.cursor_pos());
model.SelectAll(); model.SelectAll();
EXPECT_STR_EQ("GOODBYE", model.GetSelectedText()); EXPECT_STR_EQ("GOODBYE", model.GetSelectedText());
// Selection move the current pos to the begining. // Selection move the current pos to the end.
EXPECT_EQ(7U, model.cursor_pos());
model.MoveCursorToStart(false);
EXPECT_EQ(0U, model.cursor_pos()); EXPECT_EQ(0U, model.cursor_pos());
model.MoveCursorToEnd(false); model.MoveCursorToEnd(false);
EXPECT_EQ(7U, model.cursor_pos());
model.SetText(ASCIIToUTF16("BYE")); model.SetText(ASCIIToUTF16("BYE"));
EXPECT_EQ(3U, model.cursor_pos()); EXPECT_EQ(3U, model.cursor_pos());
...@@ -342,7 +348,7 @@ TEST_F(TextfieldViewsModelTest, Clipboard) { ...@@ -342,7 +348,7 @@ TEST_F(TextfieldViewsModelTest, Clipboard) {
clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text); clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text);
EXPECT_STR_EQ("HELLO HELLO WORLD", clipboard_text); EXPECT_STR_EQ("HELLO HELLO WORLD", clipboard_text);
EXPECT_STR_EQ("HELLO HELLO WORLD", model.text()); EXPECT_STR_EQ("HELLO HELLO WORLD", model.text());
EXPECT_EQ(0U, model.cursor_pos()); EXPECT_EQ(17U, model.cursor_pos());
// Test for paste. // Test for paste.
model.ClearSelection(); model.ClearSelection();
......
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