Chromium Code Reviews| Index: ui/views/controls/textfield/textfield.cc |
| diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc |
| index f3f58593762e27544c5edf5a8c10c871a0fb5ae6..d1a357da60e063d85a22e9dde6548db3ab12d447 100644 |
| --- a/ui/views/controls/textfield/textfield.cc |
| +++ b/ui/views/controls/textfield/textfield.cc |
| @@ -424,124 +424,115 @@ bool Textfield::OnKeyPressed(const ui::KeyEvent& event) { |
| if (handled) |
| return true; |
| - // TODO(oshima): Refactor and consolidate with ExecuteCommand. |
| if (event.type() == ui::ET_KEY_PRESSED) { |
| ui::KeyboardCode key_code = event.key_code(); |
| if (key_code == ui::VKEY_TAB || event.IsUnicodeKeyCode()) |
| return false; |
| - gfx::RenderText* render_text = GetRenderText(); |
| - const bool editable = !read_only(); |
| - const bool readable = text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD; |
| const bool shift = event.IsShiftDown(); |
| const bool control = event.IsControlDown(); |
| const bool alt = event.IsAltDown() || event.IsAltGrDown(); |
| - bool text_changed = false; |
| - bool cursor_changed = false; |
| + // TODO(msw): Make a helper CommandForKeyEvent or similar. |
| OnBeforeUserAction(); |
| switch (key_code) { |
| case ui::VKEY_Z: |
| - if (control && !shift && !alt && editable) |
| - cursor_changed = text_changed = model_->Undo(); |
| - else if (control && shift && !alt && editable) |
| - cursor_changed = text_changed = model_->Redo(); |
| + if (control && !shift && !alt) |
| + ExecuteCommand(IDS_APP_UNDO); |
| + else if (control && shift && !alt) |
| + ExecuteCommand(IDS_APP_REDO); |
| break; |
| case ui::VKEY_Y: |
| - if (control && !alt && editable) |
| - cursor_changed = text_changed = model_->Redo(); |
| + if (control && !alt) |
| + ExecuteCommand(IDS_APP_REDO); |
| break; |
| case ui::VKEY_A: |
| - if (control && !alt) { |
| - model_->SelectAll(false); |
| - UpdateSelectionClipboard(); |
| - cursor_changed = true; |
| - } |
| + if (control && !alt) |
| + ExecuteCommand(IDS_APP_SELECT_ALL); |
| break; |
| case ui::VKEY_X: |
| - if (control && !alt && editable && readable) |
| - cursor_changed = text_changed = Cut(); |
| + if (control && !alt) |
| + ExecuteCommand(IDS_APP_CUT); |
| break; |
| case ui::VKEY_C: |
| - if (control && !alt && readable) |
| - Copy(); |
| + if (control && !alt) |
| + ExecuteCommand(IDS_APP_COPY); |
| break; |
| case ui::VKEY_V: |
| - if (control && !alt && editable) |
| - cursor_changed = text_changed = Paste(); |
| + if (control && !alt) |
| + ExecuteCommand(IDS_APP_PASTE); |
| break; |
| case ui::VKEY_RIGHT: |
| - case ui::VKEY_LEFT: { |
| - // We should ignore the alt-left/right keys because alt key doesn't make |
| - // any special effects for them and they can be shortcut keys such like |
| - // forward/back of the browser history. |
| + // Ignore alt+right, which may be a browser navigation shortcut. |
| if (alt) |
| break; |
| - const gfx::Range selection_range = render_text->selection(); |
| - model_->MoveCursor( |
| - control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, |
| - (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT, |
| - shift); |
| - UpdateSelectionClipboard(); |
| - cursor_changed = render_text->selection() != selection_range; |
| + if (shift) { |
| + ExecuteCommand(control ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION : |
| + IDS_MOVE_RIGHT_AND_MODIFY_SELECTION); |
| + } else { |
| + ExecuteCommand(control ? IDS_MOVE_WORD_RIGHT : IDS_MOVE_RIGHT); |
| + } |
| + break; |
| + case ui::VKEY_LEFT: |
| + // Ignore alt+left, which may be a browser navigation shortcut. |
| + if (alt) |
| + break; |
| + if (shift) { |
| + ExecuteCommand(control ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION : |
| + IDS_MOVE_LEFT_AND_MODIFY_SELECTION); |
| + } else { |
| + ExecuteCommand(control ? IDS_MOVE_WORD_LEFT : IDS_MOVE_LEFT); |
| + } |
| break; |
| - } |
| - case ui::VKEY_END: |
| case ui::VKEY_HOME: |
| - if ((key_code == ui::VKEY_HOME) == |
| - (render_text->GetTextDirection() == base::i18n::RIGHT_TO_LEFT)) |
| - model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, shift); |
| - else |
| - model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, shift); |
| - UpdateSelectionClipboard(); |
| - cursor_changed = true; |
| + ExecuteCommand(shift ? IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION : |
| + IDS_MOVE_TO_BEGINNING_OF_LINE); |
| + break; |
| + case ui::VKEY_END: |
| + ExecuteCommand(shift? IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION : |
| + IDS_MOVE_TO_END_OF_LINE); |
| break; |
| case ui::VKEY_BACK: |
| + if (control && !model_->HasSelection()) { |
| + if (shift) { |
| +#if defined(OS_LINUX) |
| + // Only erase by line break on Linux and ChromeOS. |
| + ExecuteCommand(IDS_DELETE_TO_BEGINNING_OF_LINE); |
| +#endif |
| + } else { |
| + ExecuteCommand(IDS_DELETE_WORD_BACKWARD); |
| + } |
| + } else { |
| + ExecuteCommand(IDS_DELETE_BACKWARD); |
| + } |
| + break; |
| case ui::VKEY_DELETE: |
| - if (!editable) |
| - break; |
| - if (!model_->HasSelection()) { |
| - gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ? |
| - gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT; |
| - if (shift && control) { |
| - // If shift and control are pressed, erase up to the next line break |
| - // on Linux and ChromeOS. Otherwise, do nothing. |
| + if (control && !model_->HasSelection()) { |
| + if (shift) { |
| #if defined(OS_LINUX) |
| - model_->MoveCursor(gfx::LINE_BREAK, direction, true); |
| -#else |
| - break; |
| + // Only erase by line break on Linux and ChromeOS. |
| + ExecuteCommand(IDS_DELETE_TO_END_OF_LINE); |
| #endif |
| - } else if (control) { |
| - // If only control is pressed, then erase the previous/next word. |
| - model_->MoveCursor(gfx::WORD_BREAK, direction, true); |
| + } else { |
| + ExecuteCommand(IDS_DELETE_WORD_FORWARD); |
| } |
| + } else if (shift && model_->HasSelection()) { |
| + ExecuteCommand(IDS_APP_CUT); |
| + } else { |
| + ExecuteCommand(IDS_DELETE_FORWARD); |
| } |
| - if (key_code == ui::VKEY_BACK) |
| - model_->Backspace(); |
| - else if (shift && model_->HasSelection() && readable) |
| - Cut(); |
| - else |
| - model_->Delete(); |
| - |
| - // Consume backspace and delete keys even if the edit did nothing. This |
| - // prevents potential unintended side-effects of further event handling. |
| - text_changed = true; |
| break; |
| case ui::VKEY_INSERT: |
| - if (control && !shift && readable) |
| - Copy(); |
| - else if (shift && !control && editable) |
| - cursor_changed = text_changed = Paste(); |
| + if (control && !shift) |
| + ExecuteCommand(IDS_APP_COPY); |
| + else if (shift && !control) |
| + ExecuteCommand(IDS_APP_PASTE); |
| break; |
| default: |
| - break; |
| + return false; |
| } |
| - // We must have input method in order to support text input. |
| - DCHECK(GetInputMethod()); |
| - UpdateAfterChange(text_changed, cursor_changed); |
| - OnAfterUserAction(); |
| - return (text_changed || cursor_changed); |
| + return true; |
| } |
| return false; |
| } |
| @@ -960,6 +951,8 @@ bool Textfield::IsCommandIdEnabled(int command_id) const { |
| switch (command_id) { |
| case IDS_APP_UNDO: |
| return editable && model_->CanUndo(); |
| + case IDS_APP_REDO: |
| + return editable && model_->CanRedo(); |
| case IDS_APP_CUT: |
| return editable && readable && model_->HasSelection(); |
| case IDS_APP_COPY: |
| @@ -972,6 +965,26 @@ bool Textfield::IsCommandIdEnabled(int command_id) const { |
| return editable && model_->HasSelection(); |
| case IDS_APP_SELECT_ALL: |
| return !text().empty(); |
| + case IDS_DELETE_FORWARD: |
| + case IDS_DELETE_BACKWARD: |
| + case IDS_DELETE_TO_BEGINNING_OF_LINE: |
| + case IDS_DELETE_TO_END_OF_LINE: |
| + case IDS_DELETE_WORD_BACKWARD: |
| + case IDS_DELETE_WORD_FORWARD: |
| + return editable; |
| + case IDS_MOVE_LEFT: |
| + case IDS_MOVE_LEFT_AND_MODIFY_SELECTION: |
|
Elliot Glaysher
2014/03/28 22:47:49
So, if we're going to have versions for the events
msw
2014/03/28 22:55:29
The separate _AND_MODIFY_SELECTION commands come f
|
| + case IDS_MOVE_RIGHT: |
| + case IDS_MOVE_RIGHT_AND_MODIFY_SELECTION: |
| + case IDS_MOVE_WORD_LEFT: |
| + case IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION: |
| + case IDS_MOVE_WORD_RIGHT: |
| + case IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION: |
| + case IDS_MOVE_TO_BEGINNING_OF_LINE: |
| + case IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION: |
| + case IDS_MOVE_TO_END_OF_LINE: |
| + case IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION: |
| + return true; |
| default: |
| return false; |
| } |
| @@ -988,31 +1001,102 @@ void Textfield::ExecuteCommand(int command_id, int event_flags) { |
| return; |
| bool text_changed = false; |
| + bool cursor_changed = false; |
| + bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT; |
| + gfx::VisualCursorDirection begin = rtl ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT; |
| + gfx::VisualCursorDirection end = rtl ? gfx::CURSOR_LEFT : gfx::CURSOR_RIGHT; |
| + gfx::Range selection_range = GetSelectedRange(); |
| + |
| OnBeforeUserAction(); |
| switch (command_id) { |
| case IDS_APP_UNDO: |
| - text_changed = model_->Undo(); |
| + text_changed = cursor_changed = model_->Undo(); |
| + break; |
| + case IDS_APP_REDO: |
| + text_changed = cursor_changed = model_->Redo(); |
| break; |
| case IDS_APP_CUT: |
| - text_changed = Cut(); |
| + text_changed = cursor_changed = Cut(); |
| break; |
| case IDS_APP_COPY: |
| Copy(); |
| break; |
| case IDS_APP_PASTE: |
| - text_changed = Paste(); |
| + text_changed = cursor_changed = Paste(); |
| break; |
| case IDS_APP_DELETE: |
| - text_changed = model_->Delete(); |
| + text_changed = cursor_changed = model_->Delete(); |
| break; |
| case IDS_APP_SELECT_ALL: |
| SelectAll(false); |
| break; |
| + case IDS_DELETE_BACKWARD: |
| + text_changed = cursor_changed = model_->Backspace(); |
| + break; |
| + case IDS_DELETE_FORWARD: |
| + text_changed = cursor_changed = model_->Delete(); |
| + break; |
| + case IDS_DELETE_TO_END_OF_LINE: |
| + model_->MoveCursor(gfx::LINE_BREAK, end, true); |
| + text_changed = cursor_changed = model_->Delete(); |
| + break; |
| + case IDS_DELETE_TO_BEGINNING_OF_LINE: |
| + model_->MoveCursor(gfx::LINE_BREAK, begin, true); |
| + text_changed = cursor_changed = model_->Backspace(); |
| + break; |
| + case IDS_DELETE_WORD_BACKWARD: |
| + model_->MoveCursor(gfx::WORD_BREAK, begin, true); |
| + text_changed = cursor_changed = model_->Backspace(); |
| + break; |
| + case IDS_DELETE_WORD_FORWARD: |
| + model_->MoveCursor(gfx::WORD_BREAK, end, true); |
| + text_changed = cursor_changed = model_->Delete(); |
| + break; |
| + case IDS_MOVE_LEFT: |
| + model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); |
| + break; |
| + case IDS_MOVE_LEFT_AND_MODIFY_SELECTION: |
| + model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); |
| + break; |
| + case IDS_MOVE_RIGHT: |
| + model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); |
| + break; |
| + case IDS_MOVE_RIGHT_AND_MODIFY_SELECTION: |
| + model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); |
| + break; |
| + case IDS_MOVE_WORD_LEFT: |
| + model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false); |
| + break; |
| + case IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION: |
| + model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); |
| + break; |
| + case IDS_MOVE_WORD_RIGHT: |
| + model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); |
| + break; |
| + case IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION: |
| + model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); |
| + break; |
| + case IDS_MOVE_TO_BEGINNING_OF_LINE: |
| + model_->MoveCursor(gfx::LINE_BREAK, begin, false); |
| + break; |
| + case IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION: |
| + model_->MoveCursor(gfx::LINE_BREAK, begin, true); |
| + break; |
| + case IDS_MOVE_TO_END_OF_LINE: |
| + model_->MoveCursor(gfx::LINE_BREAK, end, false); |
| + break; |
| + case IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION: |
| + model_->MoveCursor(gfx::LINE_BREAK, end, true); |
| + break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| - UpdateAfterChange(text_changed, text_changed); |
| + |
| + cursor_changed |= GetSelectedRange() != selection_range; |
| + if (cursor_changed) |
| + UpdateSelectionClipboard(); |
| + UpdateAfterChange(text_changed, cursor_changed); |
| OnAfterUserAction(); |
| } |