| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/autocomplete/autocomplete_edit_view_views.h" | 5 #include "chrome/browser/autocomplete/autocomplete_edit_view_views.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "chrome/app/chrome_command_ids.h" | 10 #include "chrome/app/chrome_command_ids.h" |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 CommandUpdater* command_updater, | 114 CommandUpdater* command_updater, |
| 115 bool popup_window_mode, | 115 bool popup_window_mode, |
| 116 const views::View* location_bar) | 116 const views::View* location_bar) |
| 117 : model_(new AutocompleteEditModel(this, controller, profile)), | 117 : model_(new AutocompleteEditModel(this, controller, profile)), |
| 118 popup_view_(CreatePopupView(profile, location_bar)), | 118 popup_view_(CreatePopupView(profile, location_bar)), |
| 119 controller_(controller), | 119 controller_(controller), |
| 120 toolbar_model_(toolbar_model), | 120 toolbar_model_(toolbar_model), |
| 121 command_updater_(command_updater), | 121 command_updater_(command_updater), |
| 122 popup_window_mode_(popup_window_mode), | 122 popup_window_mode_(popup_window_mode), |
| 123 security_level_(ToolbarModel::NONE), | 123 security_level_(ToolbarModel::NONE), |
| 124 delete_was_pressed_(false), | 124 ime_composing_before_change_(false), |
| 125 delete_at_end_pressed_(false) { | 125 delete_at_end_pressed_(false) { |
| 126 set_border(views::Border::CreateEmptyBorder(kAutocompleteVerticalMargin, 0, | 126 set_border(views::Border::CreateEmptyBorder(kAutocompleteVerticalMargin, 0, |
| 127 kAutocompleteVerticalMargin, 0)); | 127 kAutocompleteVerticalMargin, 0)); |
| 128 } | 128 } |
| 129 | 129 |
| 130 AutocompleteEditViewViews::~AutocompleteEditViewViews() { | 130 AutocompleteEditViewViews::~AutocompleteEditViewViews() { |
| 131 NotificationService::current()->Notify( | 131 NotificationService::current()->Notify( |
| 132 NotificationType::AUTOCOMPLETE_EDIT_DESTROYED, | 132 NotificationType::AUTOCOMPLETE_EDIT_DESTROYED, |
| 133 Source<AutocompleteEditViewViews>(this), | 133 Source<AutocompleteEditViewViews>(this), |
| 134 NotificationService::NoDetails()); | 134 NotificationService::NoDetails()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 157 } | 157 } |
| 158 | 158 |
| 159 void AutocompleteEditViewViews::SetBaseColor() { | 159 void AutocompleteEditViewViews::SetBaseColor() { |
| 160 // TODO(oshima): Implment style change. | 160 // TODO(oshima): Implment style change. |
| 161 NOTIMPLEMENTED(); | 161 NOTIMPLEMENTED(); |
| 162 } | 162 } |
| 163 | 163 |
| 164 bool AutocompleteEditViewViews::HandleAfterKeyEvent( | 164 bool AutocompleteEditViewViews::HandleAfterKeyEvent( |
| 165 const views::KeyEvent& event, | 165 const views::KeyEvent& event, |
| 166 bool handled) { | 166 bool handled) { |
| 167 handling_key_press_ = false; | |
| 168 if (content_maybe_changed_by_key_press_) | |
| 169 OnAfterPossibleChange(); | |
| 170 | |
| 171 if (event.key_code() == ui::VKEY_RETURN) { | 167 if (event.key_code() == ui::VKEY_RETURN) { |
| 172 bool alt_held = event.IsAltDown(); | 168 bool alt_held = event.IsAltDown(); |
| 173 model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false); | 169 model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false); |
| 174 handled = true; | 170 handled = true; |
| 175 } else if (!handled && event.key_code() == ui::VKEY_ESCAPE) { | 171 } else if (!handled && event.key_code() == ui::VKEY_ESCAPE) { |
| 176 // We can handle the Escape key if textfield did not handle it. | 172 // We can handle the Escape key if textfield did not handle it. |
| 177 // If it's not handled by us, then we need to propagate it up to the parent | 173 // If it's not handled by us, then we need to propagate it up to the parent |
| 178 // widgets, so that Escape accelerator can still work. | 174 // widgets, so that Escape accelerator can still work. |
| 179 handled = model_->OnEscapeKeyPressed(); | 175 handled = model_->OnEscapeKeyPressed(); |
| 180 } else if (event.key_code() == ui::VKEY_CONTROL) { | 176 } else if (event.key_code() == ui::VKEY_CONTROL) { |
| 181 // Omnibox2 can switch its contents while pressing a control key. To switch | 177 // Omnibox2 can switch its contents while pressing a control key. To switch |
| 182 // the contents of omnibox2, we notify the AutocompleteEditModel class when | 178 // the contents of omnibox2, we notify the AutocompleteEditModel class when |
| 183 // the control-key state is changed. | 179 // the control-key state is changed. |
| 184 model_->OnControlKeyChanged(true); | 180 model_->OnControlKeyChanged(true); |
| 185 } else if (!text_changed_ && event.key_code() == ui::VKEY_DELETE && | 181 } else if (!handled && event.key_code() == ui::VKEY_DELETE && |
| 186 event.IsShiftDown()) { | 182 event.IsShiftDown()) { |
| 187 // If shift+del didn't change the text, we let this delete an entry from | 183 // If shift+del didn't change the text, we let this delete an entry from |
| 188 // the popup. We can't check to see if the IME handled it because even if | 184 // the popup. We can't check to see if the IME handled it because even if |
| 189 // nothing is selected, the IME or the TextView still report handling it. | 185 // nothing is selected, the IME or the TextView still report handling it. |
| 190 if (model_->popup_model()->IsOpen()) | 186 if (model_->popup_model()->IsOpen()) |
| 191 model_->popup_model()->TryDeletingCurrentItem(); | 187 model_->popup_model()->TryDeletingCurrentItem(); |
| 192 } else if (!handled && event.key_code() == ui::VKEY_UP) { | 188 } else if (!handled && event.key_code() == ui::VKEY_UP) { |
| 193 model_->OnUpOrDownKeyPressed(-1); | 189 model_->OnUpOrDownKeyPressed(-1); |
| 194 handled = true; | 190 handled = true; |
| 195 } else if (!handled && event.key_code() == ui::VKEY_DOWN) { | 191 } else if (!handled && event.key_code() == ui::VKEY_DOWN) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 model_->OnWillKillFocus(NULL); | 244 model_->OnWillKillFocus(NULL); |
| 249 // Close the popup. | 245 // Close the popup. |
| 250 ClosePopup(); | 246 ClosePopup(); |
| 251 // Tell the model to reset itself. | 247 // Tell the model to reset itself. |
| 252 model_->OnKillFocus(); | 248 model_->OnKillFocus(); |
| 253 controller_->OnKillFocus(); | 249 controller_->OnKillFocus(); |
| 254 } | 250 } |
| 255 | 251 |
| 256 //////////////////////////////////////////////////////////////////////////////// | 252 //////////////////////////////////////////////////////////////////////////////// |
| 257 // AutocompleteEditViewViews, views::View implementation: | 253 // AutocompleteEditViewViews, views::View implementation: |
| 258 | |
| 259 bool AutocompleteEditViewViews::OnMousePressed( | |
| 260 const views::MouseEvent& event) { | |
| 261 if (event.IsLeftMouseButton()) { | |
| 262 // Button press event may change the selection, we need to record the change | |
| 263 // and report it to |model_| later when button is released. | |
| 264 OnBeforePossibleChange(); | |
| 265 } | |
| 266 // Pass the event through to TextfieldViews. | |
| 267 return false; | |
| 268 } | |
| 269 | |
| 270 void AutocompleteEditViewViews::Layout() { | 254 void AutocompleteEditViewViews::Layout() { |
| 271 gfx::Insets insets = GetInsets(); | 255 gfx::Insets insets = GetInsets(); |
| 272 textfield_->SetBounds(insets.left(), insets.top(), | 256 textfield_->SetBounds(insets.left(), insets.top(), |
| 273 width() - insets.width(), | 257 width() - insets.width(), |
| 274 height() - insets.height()); | 258 height() - insets.height()); |
| 275 } | 259 } |
| 276 | 260 |
| 277 void AutocompleteEditViewViews::GetAccessibleState( | 261 void AutocompleteEditViewViews::GetAccessibleState( |
| 278 ui::AccessibleViewState* state) { | 262 ui::AccessibleViewState* state) { |
| 279 state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION); | 263 state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 | 455 |
| 472 void AutocompleteEditViewViews::OnRevertTemporaryText() { | 456 void AutocompleteEditViewViews::OnRevertTemporaryText() { |
| 473 textfield_->SelectRange(saved_temporary_selection_); | 457 textfield_->SelectRange(saved_temporary_selection_); |
| 474 TextChanged(); | 458 TextChanged(); |
| 475 } | 459 } |
| 476 | 460 |
| 477 void AutocompleteEditViewViews::OnBeforePossibleChange() { | 461 void AutocompleteEditViewViews::OnBeforePossibleChange() { |
| 478 // Record our state. | 462 // Record our state. |
| 479 text_before_change_ = GetText(); | 463 text_before_change_ = GetText(); |
| 480 textfield_->GetSelectedRange(&sel_before_change_); | 464 textfield_->GetSelectedRange(&sel_before_change_); |
| 465 ime_composing_before_change_ = textfield_->IsIMEComposing(); |
| 481 } | 466 } |
| 482 | 467 |
| 483 bool AutocompleteEditViewViews::OnAfterPossibleChange() { | 468 bool AutocompleteEditViewViews::OnAfterPossibleChange() { |
| 484 // OnAfterPossibleChange should be called once per modification, | |
| 485 // and we should ignore if this is called while a key event is being handled | |
| 486 // because OnAfterPossibleChagne will be called after the key event is | |
| 487 // actually handled. | |
| 488 if (handling_key_press_) { | |
| 489 content_maybe_changed_by_key_press_ = true; | |
| 490 return false; | |
| 491 } | |
| 492 ui::Range new_sel; | 469 ui::Range new_sel; |
| 493 textfield_->GetSelectedRange(&new_sel); | 470 textfield_->GetSelectedRange(&new_sel); |
| 494 | 471 |
| 495 size_t length = GetTextLength(); | 472 size_t length = GetTextLength(); |
| 496 bool at_end_of_edit = (new_sel.start() == length && new_sel.end() == length); | 473 bool at_end_of_edit = (new_sel.start() == length && new_sel.end() == length); |
| 497 | 474 |
| 498 // See if the text or selection have changed since OnBeforePossibleChange(). | 475 // See if the text or selection have changed since OnBeforePossibleChange(). |
| 499 string16 new_text = GetText(); | 476 string16 new_text = GetText(); |
| 500 text_changed_ = (new_text != text_before_change_); | 477 bool text_changed = (new_text != text_before_change_) || |
| 478 (ime_composing_before_change_ != textfield_->IsIMEComposing()); |
| 501 bool selection_differs = | 479 bool selection_differs = |
| 502 !((sel_before_change_.is_empty() && new_sel.is_empty()) || | 480 !((sel_before_change_.is_empty() && new_sel.is_empty()) || |
| 503 sel_before_change_.EqualsIgnoringDirection(new_sel)); | 481 sel_before_change_.EqualsIgnoringDirection(new_sel)); |
| 504 | 482 |
| 505 // When the user has deleted text, we don't allow inline autocomplete. Make | 483 // When the user has deleted text, we don't allow inline autocomplete. Make |
| 506 // sure to not flag cases like selecting part of the text and then pasting | 484 // sure to not flag cases like selecting part of the text and then pasting |
| 507 // (or typing) the prefix of that selection. (We detect these by making | 485 // (or typing) the prefix of that selection. (We detect these by making |
| 508 // sure the caret, which should be after any insertion, hasn't moved | 486 // sure the caret, which should be after any insertion, hasn't moved |
| 509 // forward of the old selection start.) | 487 // forward of the old selection start.) |
| 510 bool just_deleted_text = | 488 bool just_deleted_text = |
| 511 (text_before_change_.length() > new_text.length()) && | 489 (text_before_change_.length() > new_text.length()) && |
| 512 (new_sel.start() <= sel_before_change_.GetMin()); | 490 (new_sel.start() <= sel_before_change_.GetMin()); |
| 513 | 491 |
| 514 delete_at_end_pressed_ = false; | |
| 515 | |
| 516 bool something_changed = model_->OnAfterPossibleChange(new_text, | 492 bool something_changed = model_->OnAfterPossibleChange(new_text, |
| 517 selection_differs, text_changed_, just_deleted_text, at_end_of_edit); | 493 selection_differs, text_changed, just_deleted_text, at_end_of_edit); |
| 518 | 494 |
| 519 // If only selection was changed, we don't need to call |model_|'s | 495 // If only selection was changed, we don't need to call |model_|'s |
| 520 // OnChanged() method, which is called in TextChanged(). | 496 // OnChanged() method, which is called in TextChanged(). |
| 521 // But we still need to call EmphasizeURLComponents() to make sure the text | 497 // But we still need to call EmphasizeURLComponents() to make sure the text |
| 522 // attributes are updated correctly. | 498 // attributes are updated correctly. |
| 523 if (something_changed && text_changed_) { | 499 if (something_changed && text_changed) |
| 524 TextChanged(); | 500 TextChanged(); |
| 525 } else if (selection_differs) { | 501 else if (selection_differs) |
| 526 EmphasizeURLComponents(); | 502 EmphasizeURLComponents(); |
| 527 } else if (delete_was_pressed_ && at_end_of_edit) { | 503 else if (delete_at_end_pressed_) |
| 528 delete_at_end_pressed_ = true; | |
| 529 model_->OnChanged(); | 504 model_->OnChanged(); |
| 530 } | |
| 531 delete_was_pressed_ = false; | |
| 532 | 505 |
| 533 return something_changed; | 506 return something_changed; |
| 534 } | 507 } |
| 535 | 508 |
| 536 gfx::NativeView AutocompleteEditViewViews::GetNativeView() const { | 509 gfx::NativeView AutocompleteEditViewViews::GetNativeView() const { |
| 537 return GetWidget()->GetNativeView(); | 510 return GetWidget()->GetNativeView(); |
| 538 } | 511 } |
| 539 | 512 |
| 540 CommandUpdater* AutocompleteEditViewViews::GetCommandUpdater() { | 513 CommandUpdater* AutocompleteEditViewViews::GetCommandUpdater() { |
| 541 return command_updater_; | 514 return command_updater_; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 const NotificationDetails& details) { | 553 const NotificationDetails& details) { |
| 581 DCHECK(type == NotificationType::BROWSER_THEME_CHANGED); | 554 DCHECK(type == NotificationType::BROWSER_THEME_CHANGED); |
| 582 SetBaseColor(); | 555 SetBaseColor(); |
| 583 } | 556 } |
| 584 | 557 |
| 585 //////////////////////////////////////////////////////////////////////////////// | 558 //////////////////////////////////////////////////////////////////////////////// |
| 586 // AutocompleteEditViewViews, views::TextfieldController implementation: | 559 // AutocompleteEditViewViews, views::TextfieldController implementation: |
| 587 | 560 |
| 588 void AutocompleteEditViewViews::ContentsChanged(views::Textfield* sender, | 561 void AutocompleteEditViewViews::ContentsChanged(views::Textfield* sender, |
| 589 const string16& new_contents) { | 562 const string16& new_contents) { |
| 590 if (handling_key_press_) | |
| 591 content_maybe_changed_by_key_press_ = true; | |
| 592 } | 563 } |
| 593 | 564 |
| 594 bool AutocompleteEditViewViews::HandleKeyEvent( | 565 bool AutocompleteEditViewViews::HandleKeyEvent( |
| 595 views::Textfield* textfield, | 566 views::Textfield* textfield, |
| 596 const views::KeyEvent& event) { | 567 const views::KeyEvent& event) { |
| 597 delete_was_pressed_ = event.key_code() == ui::VKEY_DELETE; | 568 delete_at_end_pressed_ = false; |
| 598 | |
| 599 // Reset |text_changed_| before passing the key event on to the text view. | |
| 600 text_changed_ = false; | |
| 601 OnBeforePossibleChange(); | |
| 602 handling_key_press_ = true; | |
| 603 content_maybe_changed_by_key_press_ = false; | |
| 604 | 569 |
| 605 if (event.key_code() == ui::VKEY_BACK) { | 570 if (event.key_code() == ui::VKEY_BACK) { |
| 606 // Checks if it's currently in keyword search mode. | 571 // Checks if it's currently in keyword search mode. |
| 607 if (model_->is_keyword_hint() || model_->keyword().empty()) | 572 if (model_->is_keyword_hint() || model_->keyword().empty()) |
| 608 return false; | 573 return false; |
| 609 // If there is selection, let textfield handle the backspace. | 574 // If there is selection, let textfield handle the backspace. |
| 610 if (!textfield_->GetSelectedText().empty()) | 575 if (textfield_->HasSelection()) |
| 611 return false; | 576 return false; |
| 612 // If not at the begining of the text, let textfield handle the backspace. | 577 // If not at the begining of the text, let textfield handle the backspace. |
| 613 if (textfield_->GetCursorPosition()) | 578 if (textfield_->GetCursorPosition()) |
| 614 return false; | 579 return false; |
| 615 model_->ClearKeyword(GetText()); | 580 model_->ClearKeyword(GetText()); |
| 616 return true; | 581 return true; |
| 617 } | 582 } |
| 618 | 583 |
| 584 if (event.key_code() == ui::VKEY_DELETE && !event.IsAltDown()) { |
| 585 delete_at_end_pressed_ = |
| 586 (!textfield_->HasSelection() && |
| 587 textfield_->GetCursorPosition() == textfield_->text().length()); |
| 588 } |
| 589 |
| 619 return false; | 590 return false; |
| 620 } | 591 } |
| 621 | 592 |
| 593 void AutocompleteEditViewViews::OnBeforeUserAction(views::Textfield* sender) { |
| 594 OnBeforePossibleChange(); |
| 595 } |
| 596 |
| 597 void AutocompleteEditViewViews::OnAfterUserAction(views::Textfield* sender) { |
| 598 OnAfterPossibleChange(); |
| 599 } |
| 600 |
| 622 //////////////////////////////////////////////////////////////////////////////// | 601 //////////////////////////////////////////////////////////////////////////////// |
| 623 // AutocompleteEditViewViews, private: | 602 // AutocompleteEditViewViews, private: |
| 624 | 603 |
| 625 size_t AutocompleteEditViewViews::GetTextLength() const { | 604 size_t AutocompleteEditViewViews::GetTextLength() const { |
| 626 // TODO(oshima): Support instant, IME. | 605 // TODO(oshima): Support instant, IME. |
| 627 return textfield_->text().length(); | 606 return textfield_->text().length(); |
| 628 } | 607 } |
| 629 | 608 |
| 630 void AutocompleteEditViewViews::EmphasizeURLComponents() { | 609 void AutocompleteEditViewViews::EmphasizeURLComponents() { |
| 631 // TODO(oshima): Update URL visual style | 610 // TODO(oshima): Update URL visual style |
| (...skipping 26 matching lines...) Expand all Loading... |
| 658 AutocompletePopupView* AutocompleteEditViewViews::CreatePopupView( | 637 AutocompletePopupView* AutocompleteEditViewViews::CreatePopupView( |
| 659 Profile* profile, | 638 Profile* profile, |
| 660 const View* location_bar) { | 639 const View* location_bar) { |
| 661 #if defined(TOUCH_UI) | 640 #if defined(TOUCH_UI) |
| 662 return new TouchAutocompletePopupContentsView( | 641 return new TouchAutocompletePopupContentsView( |
| 663 #else | 642 #else |
| 664 return new AutocompletePopupContentsView( | 643 return new AutocompletePopupContentsView( |
| 665 #endif | 644 #endif |
| 666 gfx::Font(), this, model_.get(), profile, location_bar); | 645 gfx::Font(), this, model_.get(), profile, location_bar); |
| 667 } | 646 } |
| OLD | NEW |