diff options
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_edit_view_views.cc | 71 | ||||
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_edit_view_views.h | 104 | ||||
-rw-r--r-- | views/controls/textfield/native_textfield_views.cc | 157 | ||||
-rw-r--r-- | views/controls/textfield/native_textfield_views.h | 14 | ||||
-rw-r--r-- | views/controls/textfield/textfield.cc | 7 | ||||
-rw-r--r-- | views/controls/textfield/textfield.h | 3 | ||||
-rw-r--r-- | views/controls/textfield/textfield_controller.h | 11 |
7 files changed, 134 insertions, 233 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_views.cc b/chrome/browser/autocomplete/autocomplete_edit_view_views.cc index e3626b7..76a22d4 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_views.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_views.cc @@ -121,7 +121,7 @@ AutocompleteEditViewViews::AutocompleteEditViewViews( command_updater_(command_updater), popup_window_mode_(popup_window_mode), security_level_(ToolbarModel::NONE), - delete_was_pressed_(false), + ime_composing_before_change_(false), delete_at_end_pressed_(false) { set_border(views::Border::CreateEmptyBorder(kAutocompleteVerticalMargin, 0, kAutocompleteVerticalMargin, 0)); @@ -164,10 +164,6 @@ void AutocompleteEditViewViews::SetBaseColor() { bool AutocompleteEditViewViews::HandleAfterKeyEvent( const views::KeyEvent& event, bool handled) { - handling_key_press_ = false; - if (content_maybe_changed_by_key_press_) - OnAfterPossibleChange(); - if (event.key_code() == ui::VKEY_RETURN) { bool alt_held = event.IsAltDown(); model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false); @@ -182,7 +178,7 @@ bool AutocompleteEditViewViews::HandleAfterKeyEvent( // the contents of omnibox2, we notify the AutocompleteEditModel class when // the control-key state is changed. model_->OnControlKeyChanged(true); - } else if (!text_changed_ && event.key_code() == ui::VKEY_DELETE && + } else if (!handled && event.key_code() == ui::VKEY_DELETE && event.IsShiftDown()) { // If shift+del didn't change the text, we let this delete an entry from // the popup. We can't check to see if the IME handled it because even if @@ -255,18 +251,6 @@ void AutocompleteEditViewViews::HandleFocusOut() { //////////////////////////////////////////////////////////////////////////////// // AutocompleteEditViewViews, views::View implementation: - -bool AutocompleteEditViewViews::OnMousePressed( - const views::MouseEvent& event) { - if (event.IsLeftMouseButton()) { - // Button press event may change the selection, we need to record the change - // and report it to |model_| later when button is released. - OnBeforePossibleChange(); - } - // Pass the event through to TextfieldViews. - return false; -} - void AutocompleteEditViewViews::Layout() { gfx::Insets insets = GetInsets(); textfield_->SetBounds(insets.left(), insets.top(), @@ -478,17 +462,10 @@ void AutocompleteEditViewViews::OnBeforePossibleChange() { // Record our state. text_before_change_ = GetText(); textfield_->GetSelectedRange(&sel_before_change_); + ime_composing_before_change_ = textfield_->IsIMEComposing(); } bool AutocompleteEditViewViews::OnAfterPossibleChange() { - // OnAfterPossibleChange should be called once per modification, - // and we should ignore if this is called while a key event is being handled - // because OnAfterPossibleChagne will be called after the key event is - // actually handled. - if (handling_key_press_) { - content_maybe_changed_by_key_press_ = true; - return false; - } ui::Range new_sel; textfield_->GetSelectedRange(&new_sel); @@ -497,7 +474,8 @@ bool AutocompleteEditViewViews::OnAfterPossibleChange() { // See if the text or selection have changed since OnBeforePossibleChange(). string16 new_text = GetText(); - text_changed_ = (new_text != text_before_change_); + bool text_changed = (new_text != text_before_change_) || + (ime_composing_before_change_ != textfield_->IsIMEComposing()); bool selection_differs = !((sel_before_change_.is_empty() && new_sel.is_empty()) || sel_before_change_.EqualsIgnoringDirection(new_sel)); @@ -511,24 +489,19 @@ bool AutocompleteEditViewViews::OnAfterPossibleChange() { (text_before_change_.length() > new_text.length()) && (new_sel.start() <= sel_before_change_.GetMin()); - delete_at_end_pressed_ = false; - bool something_changed = model_->OnAfterPossibleChange(new_text, - selection_differs, text_changed_, just_deleted_text, at_end_of_edit); + selection_differs, text_changed, just_deleted_text, at_end_of_edit); // If only selection was changed, we don't need to call |model_|'s // OnChanged() method, which is called in TextChanged(). // But we still need to call EmphasizeURLComponents() to make sure the text // attributes are updated correctly. - if (something_changed && text_changed_) { + if (something_changed && text_changed) TextChanged(); - } else if (selection_differs) { + else if (selection_differs) EmphasizeURLComponents(); - } else if (delete_was_pressed_ && at_end_of_edit) { - delete_at_end_pressed_ = true; + else if (delete_at_end_pressed_) model_->OnChanged(); - } - delete_was_pressed_ = false; return something_changed; } @@ -587,27 +560,19 @@ void AutocompleteEditViewViews::Observe(NotificationType type, void AutocompleteEditViewViews::ContentsChanged(views::Textfield* sender, const string16& new_contents) { - if (handling_key_press_) - content_maybe_changed_by_key_press_ = true; } bool AutocompleteEditViewViews::HandleKeyEvent( views::Textfield* textfield, const views::KeyEvent& event) { - delete_was_pressed_ = event.key_code() == ui::VKEY_DELETE; - - // Reset |text_changed_| before passing the key event on to the text view. - text_changed_ = false; - OnBeforePossibleChange(); - handling_key_press_ = true; - content_maybe_changed_by_key_press_ = false; + delete_at_end_pressed_ = false; if (event.key_code() == ui::VKEY_BACK) { // Checks if it's currently in keyword search mode. if (model_->is_keyword_hint() || model_->keyword().empty()) return false; // If there is selection, let textfield handle the backspace. - if (!textfield_->GetSelectedText().empty()) + if (textfield_->HasSelection()) return false; // If not at the begining of the text, let textfield handle the backspace. if (textfield_->GetCursorPosition()) @@ -616,9 +581,23 @@ bool AutocompleteEditViewViews::HandleKeyEvent( return true; } + if (event.key_code() == ui::VKEY_DELETE && !event.IsAltDown()) { + delete_at_end_pressed_ = + (!textfield_->HasSelection() && + textfield_->GetCursorPosition() == textfield_->text().length()); + } + return false; } +void AutocompleteEditViewViews::OnBeforeUserAction(views::Textfield* sender) { + OnBeforePossibleChange(); +} + +void AutocompleteEditViewViews::OnAfterUserAction(views::Textfield* sender) { + OnAfterPossibleChange(); +} + //////////////////////////////////////////////////////////////////////////////// // AutocompleteEditViewViews, private: diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_views.h b/chrome/browser/autocomplete/autocomplete_edit_view_views.h index 4f32ed9..92fb4b1 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_views.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_views.h @@ -66,72 +66,74 @@ class AutocompleteEditViewViews : public views::View, void HandleFocusOut(); // Implements views::View - virtual bool OnMousePressed(const views::MouseEvent& event); - virtual void Layout(); + virtual void Layout() OVERRIDE; virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE; // Implement the AutocompleteEditView interface. - virtual AutocompleteEditModel* model(); - virtual const AutocompleteEditModel* model() const; + virtual AutocompleteEditModel* model() OVERRIDE; + virtual const AutocompleteEditModel* model() const OVERRIDE; - virtual void SaveStateToTab(TabContents* tab); + virtual void SaveStateToTab(TabContents* tab) OVERRIDE; - virtual void Update(const TabContents* tab_for_state_restoring); + virtual void Update(const TabContents* tab_for_state_restoring) OVERRIDE; virtual void OpenURL(const GURL& url, WindowOpenDisposition disposition, PageTransition::Type transition, const GURL& alternate_nav_url, size_t selected_line, - const string16& keyword); + const string16& keyword) OVERRIDE; - virtual string16 GetText() const; + virtual string16 GetText() const OVERRIDE; - virtual bool IsEditingOrEmpty() const; - virtual int GetIcon() const; - virtual void SetUserText(const string16& text); + virtual bool IsEditingOrEmpty() const OVERRIDE; + virtual int GetIcon() const OVERRIDE; + virtual void SetUserText(const string16& text) OVERRIDE; virtual void SetUserText(const string16& text, const string16& display_text, - bool update_popup); + bool update_popup) OVERRIDE; virtual void SetWindowTextAndCaretPos(const string16& text, - size_t caret_pos); - virtual void SetForcedQuery(); - virtual bool IsSelectAll(); - virtual bool DeleteAtEndPressed(); + size_t caret_pos) OVERRIDE; + virtual void SetForcedQuery() OVERRIDE; + virtual bool IsSelectAll() OVERRIDE; + virtual bool DeleteAtEndPressed() OVERRIDE; virtual void GetSelectionBounds(string16::size_type* start, - string16::size_type* end); - virtual void SelectAll(bool reversed); - virtual void RevertAll(); - virtual void UpdatePopup(); - virtual void ClosePopup(); - virtual void SetFocus(); - virtual void OnTemporaryTextMaybeChanged(const string16& display_text, - bool save_original_selection); + string16::size_type* end) OVERRIDE; + virtual void SelectAll(bool reversed) OVERRIDE; + virtual void RevertAll() OVERRIDE; + virtual void UpdatePopup() OVERRIDE; + virtual void ClosePopup() OVERRIDE; + virtual void SetFocus() OVERRIDE; + virtual void OnTemporaryTextMaybeChanged( + const string16& display_text, + bool save_original_selection) OVERRIDE; virtual bool OnInlineAutocompleteTextMaybeChanged( - const string16& display_text, size_t user_text_length); - virtual void OnRevertTemporaryText(); - virtual void OnBeforePossibleChange(); - virtual bool OnAfterPossibleChange(); - virtual gfx::NativeView GetNativeView() const; - virtual CommandUpdater* GetCommandUpdater(); + const string16& display_text, size_t user_text_length) OVERRIDE; + virtual void OnRevertTemporaryText() OVERRIDE; + virtual void OnBeforePossibleChange() OVERRIDE; + virtual bool OnAfterPossibleChange() OVERRIDE; + virtual gfx::NativeView GetNativeView() const OVERRIDE; + virtual CommandUpdater* GetCommandUpdater() OVERRIDE; virtual void SetInstantSuggestion(const string16& input, - bool animate_to_complete); - virtual string16 GetInstantSuggestion() const; - virtual int TextWidth() const; - virtual bool IsImeComposing() const; - virtual views::View* AddToView(views::View* parent); - virtual int OnPerformDrop(const views::DropTargetEvent& event); + bool animate_to_complete) OVERRIDE; + virtual string16 GetInstantSuggestion() const OVERRIDE; + virtual int TextWidth() const OVERRIDE; + virtual bool IsImeComposing() const OVERRIDE; + virtual views::View* AddToView(views::View* parent) OVERRIDE; + virtual int OnPerformDrop(const views::DropTargetEvent& event) OVERRIDE; // NotificationObserver: virtual void Observe(NotificationType type, const NotificationSource& source, - const NotificationDetails& details); + const NotificationDetails& details) OVERRIDE; // views::TextfieldController: virtual void ContentsChanged(views::Textfield* sender, - const string16& new_contents); + const string16& new_contents) OVERRIDE; virtual bool HandleKeyEvent(views::Textfield* sender, - const views::KeyEvent& key_event); + const views::KeyEvent& key_event) OVERRIDE; + virtual void OnBeforeUserAction(views::Textfield* sender) OVERRIDE; + virtual void OnAfterUserAction(views::Textfield* sender) OVERRIDE; private: // Return the number of characers in the current buffer. @@ -180,33 +182,11 @@ class AutocompleteEditViewViews : public views::View, // Tracking state before and after a possible change. string16 text_before_change_; ui::Range sel_before_change_; - - // TODO(oshima): following flags are copied from gtk implementation. - // It should be possible to refactor this class to simplify flags and - // logic. I'll work on this refactoring once all features are completed. - - // Indicates whether the IME changed the text. It's possible for the IME to - // handle a key event but not change the text contents (e.g., when pressing - // shift+del with no selection). - bool text_changed_; - - // Was delete pressed? - bool delete_was_pressed_; + bool ime_composing_before_change_; // Was the delete key pressed with an empty selection at the end of the edit? bool delete_at_end_pressed_; - // Indicates if we are handling a key press event. - bool handling_key_press_; - - // Indicates if omnibox's content maybe changed by a key press event, so that - // we need to call OnAfterPossibleChange() after handling the event. - // This flag should be set for changes directly caused by a key press event, - // including changes to content text, selection range and preedit string. - // Changes caused by function calls like SetUserText() should not affect this - // flag. - bool content_maybe_changed_by_key_press_; - DISALLOW_COPY_AND_ASSIGN(AutocompleteEditViewViews); }; diff --git a/views/controls/textfield/native_textfield_views.cc b/views/controls/textfield/native_textfield_views.cc index f935193..17885ba 100644 --- a/views/controls/textfield/native_textfield_views.cc +++ b/views/controls/textfield/native_textfield_views.cc @@ -86,17 +86,21 @@ NativeTextfieldViews::~NativeTextfieldViews() { // NativeTextfieldViews, View overrides: bool NativeTextfieldViews::OnMousePressed(const views::MouseEvent& e) { + OnBeforeUserAction(); if (HandleMousePressed(e)) SchedulePaint(); + OnAfterUserAction(); return true; } bool NativeTextfieldViews::OnMouseDragged(const views::MouseEvent& e) { + OnBeforeUserAction(); size_t pos = FindCursorPosition(e.location()); if (model_->MoveCursorTo(pos, true)) { UpdateCursorBoundsAndTextOffset(); SchedulePaint(); } + OnAfterUserAction(); return true; } @@ -360,6 +364,7 @@ bool NativeTextfieldViews::GetAcceleratorForCommandId(int command_id, void NativeTextfieldViews::ExecuteCommand(int command_id) { bool text_changed = false; bool editable = !textfield_->read_only(); + OnBeforeUserAction(); switch (command_id) { case IDS_APP_CUT: if (editable) @@ -386,6 +391,7 @@ void NativeTextfieldViews::ExecuteCommand(int command_id) { // The cursor must have changed if text changed during cut/paste/delete. UpdateAfterChange(text_changed, text_changed); + OnAfterUserAction(); } // static @@ -531,6 +537,8 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { // TODO(oshima): shift-tab does not work. Figure out why and fix. if (key_code == ui::VKEY_TAB) return false; + + OnBeforeUserAction(); bool editable = !textfield_->read_only(); bool selection = key_event.IsShiftDown(); bool control = key_event.IsControlDown(); @@ -619,138 +627,22 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { default: break; } - char16 print_char = GetPrintableChar(key_event); - if (!control && print_char && editable) { + char16 ch = key_event.GetCharacter(); + if (editable && ShouldInsertChar(ch, key_event.flags())) { if (insert_) - model_->Insert(print_char); + model_->Insert(ch); else - model_->Replace(print_char); + model_->Replace(ch); text_changed = true; } UpdateAfterChange(text_changed, cursor_changed); + OnAfterUserAction(); return (text_changed || cursor_changed); } return false; } -char16 NativeTextfieldViews::GetPrintableChar(const KeyEvent& key_event) { - // TODO(oshima): IME, i18n support. - // This only works for UCS-2 characters. - ui::KeyboardCode key_code = key_event.key_code(); - bool shift = key_event.IsShiftDown(); - bool upper = shift ^ key_event.IsCapsLockDown(); - // TODO(oshima): We should have a utility function - // under app to convert a KeyboardCode to a printable character, - // probably in keyboard_code_conversion{.h, _x - switch (key_code) { - case ui::VKEY_NUMPAD0: - return '0'; - case ui::VKEY_NUMPAD1: - return '1'; - case ui::VKEY_NUMPAD2: - return '2'; - case ui::VKEY_NUMPAD3: - return '3'; - case ui::VKEY_NUMPAD4: - return '4'; - case ui::VKEY_NUMPAD5: - return '5'; - case ui::VKEY_NUMPAD6: - return '6'; - case ui::VKEY_NUMPAD7: - return '7'; - case ui::VKEY_NUMPAD8: - return '8'; - case ui::VKEY_NUMPAD9: - return '9'; - case ui::VKEY_MULTIPLY: - return '*'; - case ui::VKEY_ADD: - return '+'; - case ui::VKEY_SUBTRACT: - return '-'; - case ui::VKEY_DECIMAL: - return '.'; - case ui::VKEY_DIVIDE: - return '/'; - case ui::VKEY_SPACE: - return ' '; - case ui::VKEY_0: - return shift ? ')' : '0'; - case ui::VKEY_1: - return shift ? '!' : '1'; - case ui::VKEY_2: - return shift ? '@' : '2'; - case ui::VKEY_3: - return shift ? '#' : '3'; - case ui::VKEY_4: - return shift ? '$' : '4'; - case ui::VKEY_5: - return shift ? '%' : '5'; - case ui::VKEY_6: - return shift ? '^' : '6'; - case ui::VKEY_7: - return shift ? '&' : '7'; - case ui::VKEY_8: - return shift ? '*' : '8'; - case ui::VKEY_9: - return shift ? '(' : '9'; - - case ui::VKEY_A: - case ui::VKEY_B: - case ui::VKEY_C: - case ui::VKEY_D: - case ui::VKEY_E: - case ui::VKEY_F: - case ui::VKEY_G: - case ui::VKEY_H: - case ui::VKEY_I: - case ui::VKEY_J: - case ui::VKEY_K: - case ui::VKEY_L: - case ui::VKEY_M: - case ui::VKEY_N: - case ui::VKEY_O: - case ui::VKEY_P: - case ui::VKEY_Q: - case ui::VKEY_R: - case ui::VKEY_S: - case ui::VKEY_T: - case ui::VKEY_U: - case ui::VKEY_V: - case ui::VKEY_W: - case ui::VKEY_X: - case ui::VKEY_Y: - case ui::VKEY_Z: - return (upper ? 'A' : 'a') + (key_code - ui::VKEY_A); - case ui::VKEY_OEM_1: - return shift ? ':' : ';'; - case ui::VKEY_OEM_PLUS: - return shift ? '+' : '='; - case ui::VKEY_OEM_COMMA: - return shift ? '<' : ','; - case ui::VKEY_OEM_MINUS: - return shift ? '_' : '-'; - case ui::VKEY_OEM_PERIOD: - return shift ? '>' : '.'; - case ui::VKEY_OEM_2: - return shift ? '?' : '/'; - case ui::VKEY_OEM_3: - return shift ? '~' : '`'; - case ui::VKEY_OEM_4: - return shift ? '}' : ']'; - case ui::VKEY_OEM_5: - return shift ? '|' : '\\'; - case ui::VKEY_OEM_6: - return shift ? '{' : '['; - case ui::VKEY_OEM_7: - return shift ? '"' : '\''; - default: - return 0; - } -} - size_t NativeTextfieldViews::FindCursorPosition(const gfx::Point& point) const { // TODO(oshima): BIDI/i18n support. gfx::Font font = GetFont(); @@ -859,6 +751,29 @@ void NativeTextfieldViews::InitContextMenuIfRequired() { context_menu_menu_.reset(new Menu2(context_menu_contents_.get())); } +void NativeTextfieldViews::OnBeforeUserAction() { + TextfieldController* controller = textfield_->GetController(); + if (controller) + controller->OnBeforeUserAction(textfield_); +} + +void NativeTextfieldViews::OnAfterUserAction() { + TextfieldController* controller = textfield_->GetController(); + if (controller) + controller->OnAfterUserAction(textfield_); +} + +// static +bool NativeTextfieldViews::ShouldInsertChar(char16 ch, int flags) { + // Filter out all control characters, including tab and new line characters, + // and all characters with Alt modifier. But we need to allow characters with + // AltGr modifier. + // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different + // flag that we don't care about. + return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) && + (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN; +} + /////////////////////////////////////////////////////////////////////////////// // // TextifieldBorder diff --git a/views/controls/textfield/native_textfield_views.h b/views/controls/textfield/native_textfield_views.h index 1f80147..7cc8317f 100644 --- a/views/controls/textfield/native_textfield_views.h +++ b/views/controls/textfield/native_textfield_views.h @@ -169,10 +169,6 @@ class NativeTextfieldViews : public views::View, // Handle the keyevent. bool HandleKeyEvent(const KeyEvent& key_event); - // Utility function. Gets the character corresponding to a keyevent. - // Returns 0 if the character is not printable. - char16 GetPrintableChar(const KeyEvent& key_event); - // Find a cusor position for given |point| in this views coordinates. size_t FindCursorPosition(const gfx::Point& point) const; @@ -194,6 +190,16 @@ class NativeTextfieldViews : public views::View, // Utility function to create the context menu if one does not already exist. void InitContextMenuIfRequired(); + // Convenience method to call TextfieldController::OnBeforeUserAction(); + void OnBeforeUserAction(); + + // Convenience method to call TextfieldController::OnAfterUserAction(); + void OnAfterUserAction(); + + // Checks if a char is ok to be inserted into the textfield. The |ch| is a + // modified character, i.e., modifiers took effect when generating this char. + static bool ShouldInsertChar(char16 ch, int flags); + // The parent textfield, the owner of this object. Textfield* textfield_; diff --git a/views/controls/textfield/textfield.cc b/views/controls/textfield/textfield.cc index ec99e77..7dfa4da 100644 --- a/views/controls/textfield/textfield.cc +++ b/views/controls/textfield/textfield.cc @@ -141,6 +141,13 @@ void Textfield::ClearSelection() const { native_wrapper_->ClearSelection(); } +bool Textfield::HasSelection() const { + ui::Range range; + if (native_wrapper_) + native_wrapper_->GetSelectedRange(&range); + return !range.is_empty(); +} + void Textfield::SetTextColor(SkColor color) { text_color_ = color; use_default_text_color_ = false; diff --git a/views/controls/textfield/textfield.h b/views/controls/textfield/textfield.h index ca87bdf..bbea47d 100644 --- a/views/controls/textfield/textfield.h +++ b/views/controls/textfield/textfield.h @@ -89,6 +89,9 @@ class Textfield : public View { // Clears the selection within the edit field and sets the caret to the end. void ClearSelection() const; + // Checks if there is any selected text. + bool HasSelection() const; + // Accessor for |style_|. StyleFlags style() const { return style_; } diff --git a/views/controls/textfield/textfield_controller.h b/views/controls/textfield/textfield_controller.h index 53fe97c..ee8df1b 100644 --- a/views/controls/textfield/textfield_controller.h +++ b/views/controls/textfield/textfield_controller.h @@ -26,6 +26,17 @@ class TextfieldController { // further. If it returns false the processing continues. virtual bool HandleKeyEvent(Textfield* sender, const KeyEvent& key_event) = 0; + + // Called before performing a user action that may change the textfield. + // It's currently only supported by Views implementation. + virtual void OnBeforeUserAction(Textfield* sender) {} + + // Called after performing a user action that may change the textfield. + // It's currently only supported by Views implementation. + virtual void OnAfterUserAction(Textfield* sender) {} + + protected: + virtual ~TextfieldController() {} }; } // namespace views |