Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(237)

Side by Side Diff: chrome/browser/autocomplete/autocomplete_edit.cc

Issue 6252003: Accept keyword by pressing space. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix a bug on Windows when using an IME. Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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.h" 5 #include "chrome/browser/autocomplete/autocomplete_edit.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 27 matching lines...) Expand all
38 38
39 AutocompleteEditController::~AutocompleteEditController() { 39 AutocompleteEditController::~AutocompleteEditController() {
40 } 40 }
41 41
42 /////////////////////////////////////////////////////////////////////////////// 42 ///////////////////////////////////////////////////////////////////////////////
43 // AutocompleteEditModel::State 43 // AutocompleteEditModel::State
44 44
45 AutocompleteEditModel::State::State(bool user_input_in_progress, 45 AutocompleteEditModel::State::State(bool user_input_in_progress,
46 const std::wstring& user_text, 46 const std::wstring& user_text,
47 const std::wstring& keyword, 47 const std::wstring& keyword,
48 bool is_keyword_hint, 48 bool is_keyword_hint)
49 KeywordUIState keyword_ui_state)
50 : user_input_in_progress(user_input_in_progress), 49 : user_input_in_progress(user_input_in_progress),
51 user_text(user_text), 50 user_text(user_text),
52 keyword(keyword), 51 keyword(keyword),
53 is_keyword_hint(is_keyword_hint), 52 is_keyword_hint(is_keyword_hint) {
54 keyword_ui_state(keyword_ui_state) {
55 } 53 }
56 54
57 AutocompleteEditModel::State::~State() { 55 AutocompleteEditModel::State::~State() {
58 } 56 }
59 57
60 /////////////////////////////////////////////////////////////////////////////// 58 ///////////////////////////////////////////////////////////////////////////////
61 // AutocompleteEditModel 59 // AutocompleteEditModel
62 60
63 AutocompleteEditModel::AutocompleteEditModel( 61 AutocompleteEditModel::AutocompleteEditModel(
64 AutocompleteEditView* view, 62 AutocompleteEditView* view,
65 AutocompleteEditController* controller, 63 AutocompleteEditController* controller,
66 Profile* profile) 64 Profile* profile)
67 : view_(view), 65 : view_(view),
68 popup_(NULL), 66 popup_(NULL),
69 controller_(controller), 67 controller_(controller),
70 has_focus_(false), 68 has_focus_(false),
71 user_input_in_progress_(false), 69 user_input_in_progress_(false),
72 just_deleted_text_(false), 70 just_deleted_text_(false),
73 has_temporary_text_(false), 71 has_temporary_text_(false),
74 original_keyword_ui_state_(NORMAL),
75 paste_state_(NONE), 72 paste_state_(NONE),
76 control_key_state_(UP), 73 control_key_state_(UP),
77 is_keyword_hint_(false), 74 is_keyword_hint_(false),
78 keyword_ui_state_(NORMAL),
79 paste_and_go_transition_(PageTransition::TYPED), 75 paste_and_go_transition_(PageTransition::TYPED),
80 profile_(profile) { 76 profile_(profile) {
81 } 77 }
82 78
83 AutocompleteEditModel::~AutocompleteEditModel() { 79 AutocompleteEditModel::~AutocompleteEditModel() {
84 } 80 }
85 81
86 void AutocompleteEditModel::SetPopupModel(AutocompletePopupModel* popup_model) { 82 void AutocompleteEditModel::SetPopupModel(AutocompletePopupModel* popup_model) {
87 popup_ = popup_model; 83 popup_ = popup_model;
88 registrar_.Add(this, 84 registrar_.Add(this,
(...skipping 18 matching lines...) Expand all
107 // on switching back, typing will "just work"). 103 // on switching back, typing will "just work").
108 const std::wstring user_text(UserTextFromDisplayText(view_->GetText())); 104 const std::wstring user_text(UserTextFromDisplayText(view_->GetText()));
109 if (user_text.empty()) { 105 if (user_text.empty()) {
110 view_->RevertAll(); 106 view_->RevertAll();
111 view_->SelectAll(true); 107 view_->SelectAll(true);
112 } else { 108 } else {
113 InternalSetUserText(user_text); 109 InternalSetUserText(user_text);
114 } 110 }
115 } 111 }
116 112
117 return State(user_input_in_progress_, user_text_, keyword_, is_keyword_hint_, 113 return State(user_input_in_progress_, user_text_, keyword_, is_keyword_hint_);
118 keyword_ui_state_);
119 } 114 }
120 115
121 void AutocompleteEditModel::RestoreState(const State& state) { 116 void AutocompleteEditModel::RestoreState(const State& state) {
122 // Restore any user editing. 117 // Restore any user editing.
123 if (state.user_input_in_progress) { 118 if (state.user_input_in_progress) {
124 // NOTE: Be sure and set keyword-related state BEFORE invoking 119 // NOTE: Be sure and set keyword-related state BEFORE invoking
125 // DisplayTextFromUserText(), as its result depends upon this state. 120 // DisplayTextFromUserText(), as its result depends upon this state.
126 keyword_ = state.keyword; 121 keyword_ = state.keyword;
127 is_keyword_hint_ = state.is_keyword_hint; 122 is_keyword_hint_ = state.is_keyword_hint;
128 keyword_ui_state_ = state.keyword_ui_state;
129 view_->SetUserText(state.user_text, 123 view_->SetUserText(state.user_text,
130 DisplayTextFromUserText(state.user_text), false); 124 DisplayTextFromUserText(state.user_text), false);
131 } 125 }
132 } 126 }
133 127
134 AutocompleteMatch AutocompleteEditModel::CurrentMatch() { 128 AutocompleteMatch AutocompleteEditModel::CurrentMatch() {
135 AutocompleteMatch match; 129 AutocompleteMatch match;
136 GetInfoForCurrentText(&match, NULL); 130 GetInfoForCurrentText(&match, NULL);
137 return match; 131 return match;
138 } 132 }
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 user_input_in_progress_ = in_progress; 283 user_input_in_progress_ = in_progress;
290 controller_->OnInputInProgress(in_progress); 284 controller_->OnInputInProgress(in_progress);
291 } 285 }
292 286
293 void AutocompleteEditModel::Revert() { 287 void AutocompleteEditModel::Revert() {
294 SetInputInProgress(false); 288 SetInputInProgress(false);
295 paste_state_ = NONE; 289 paste_state_ = NONE;
296 InternalSetUserText(std::wstring()); 290 InternalSetUserText(std::wstring());
297 keyword_.clear(); 291 keyword_.clear();
298 is_keyword_hint_ = false; 292 is_keyword_hint_ = false;
299 keyword_ui_state_ = NORMAL;
300 has_temporary_text_ = false; 293 has_temporary_text_ = false;
301 view_->SetWindowTextAndCaretPos(permanent_text_, 294 view_->SetWindowTextAndCaretPos(permanent_text_,
302 has_focus_ ? permanent_text_.length() : 0); 295 has_focus_ ? permanent_text_.length() : 0);
303 } 296 }
304 297
305 void AutocompleteEditModel::StartAutocomplete( 298 void AutocompleteEditModel::StartAutocomplete(
306 bool has_selected_text, 299 bool has_selected_text,
307 bool prevent_inline_autocomplete) const { 300 bool prevent_inline_autocomplete) const {
301 bool keyword_is_selected = KeywordIsSelected();
308 popup_->StartAutocomplete(user_text_, GetDesiredTLD(), 302 popup_->StartAutocomplete(user_text_, GetDesiredTLD(),
309 prevent_inline_autocomplete || just_deleted_text_ || 303 prevent_inline_autocomplete || just_deleted_text_ ||
310 (has_selected_text && inline_autocomplete_text_.empty()) || 304 (has_selected_text && inline_autocomplete_text_.empty()) ||
311 (paste_state_ != NONE), keyword_ui_state_ == KEYWORD, 305 (paste_state_ == REPLACED_ALL), keyword_is_selected, keyword_is_selected);
Peter Kasting 2011/01/20 00:04:22 Let's go ahead and leave the check here as "paste_
James Su 2011/01/20 06:49:31 Done.
312 keyword_ui_state_ != NO_KEYWORD);
313 } 306 }
314 307
315 bool AutocompleteEditModel::CanPasteAndGo(const std::wstring& text) const { 308 bool AutocompleteEditModel::CanPasteAndGo(const std::wstring& text) const {
316 if (!view_->GetCommandUpdater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL)) 309 if (!view_->GetCommandUpdater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL))
317 return false; 310 return false;
318 311
319 AutocompleteMatch match; 312 AutocompleteMatch match;
320 profile_->GetAutocompleteClassifier()->Classify(text, std::wstring(), false, 313 profile_->GetAutocompleteClassifier()->Classify(text, std::wstring(), false,
321 &match, &paste_and_go_alternate_nav_url_); 314 &match, &paste_and_go_alternate_nav_url_);
322 paste_and_go_url_ = match.destination_url; 315 paste_and_go_url_ = match.destination_url;
(...skipping 26 matching lines...) Expand all
349 // When the user hit enter on the existing permanent URL, treat it like a 342 // When the user hit enter on the existing permanent URL, treat it like a
350 // reload for scoring purposes. We could detect this by just checking 343 // reload for scoring purposes. We could detect this by just checking
351 // user_input_in_progress_, but it seems better to treat "edits" that end 344 // user_input_in_progress_, but it seems better to treat "edits" that end
352 // up leaving the URL unchanged (e.g. deleting the last character and then 345 // up leaving the URL unchanged (e.g. deleting the last character and then
353 // retyping it) as reloads too. We exclude non-TYPED transitions because if 346 // retyping it) as reloads too. We exclude non-TYPED transitions because if
354 // the transition is GENERATED, the user input something that looked 347 // the transition is GENERATED, the user input something that looked
355 // different from the current URL, even if it wound up at the same place 348 // different from the current URL, even if it wound up at the same place
356 // (e.g. manually retyping the same search query), and it seems wrong to 349 // (e.g. manually retyping the same search query), and it seems wrong to
357 // treat this as a reload. 350 // treat this as a reload.
358 match.transition = PageTransition::RELOAD; 351 match.transition = PageTransition::RELOAD;
359 } else if (for_drop || ((paste_state_ != NONE) && 352 } else if (for_drop || ((paste_state_ == REPLACED_ALL) &&
360 match.is_history_what_you_typed_match)) { 353 match.is_history_what_you_typed_match)) {
361 // When the user pasted in a URL and hit enter, score it like a link click 354 // When the user pasted in a URL and hit enter, score it like a link click
362 // rather than a normal typed URL, so it doesn't get inline autocompleted 355 // rather than a normal typed URL, so it doesn't get inline autocompleted
363 // as aggressively later. 356 // as aggressively later.
364 match.transition = PageTransition::LINK; 357 match.transition = PageTransition::LINK;
365 } 358 }
366 359
367 if (match.type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED || 360 if (match.type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED ||
368 match.type == AutocompleteMatch::SEARCH_HISTORY || 361 match.type == AutocompleteMatch::SEARCH_HISTORY ||
369 match.type == AutocompleteMatch::SEARCH_SUGGEST) { 362 match.type == AutocompleteMatch::SEARCH_SUGGEST) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 425
433 if (disposition != NEW_BACKGROUND_TAB) { 426 if (disposition != NEW_BACKGROUND_TAB) {
434 controller_->OnAutocompleteWillAccept(); 427 controller_->OnAutocompleteWillAccept();
435 view_->RevertAll(); // Revert the box to its unedited state 428 view_->RevertAll(); // Revert the box to its unedited state
436 } 429 }
437 controller_->OnAutocompleteAccept(url, disposition, transition, 430 controller_->OnAutocompleteAccept(url, disposition, transition,
438 alternate_nav_url); 431 alternate_nav_url);
439 } 432 }
440 433
441 void AutocompleteEditModel::AcceptKeyword() { 434 void AutocompleteEditModel::AcceptKeyword() {
435 DCHECK(is_keyword_hint_ && !keyword_.empty());
436
442 view_->OnBeforePossibleChange(); 437 view_->OnBeforePossibleChange();
443 view_->SetWindowTextAndCaretPos(std::wstring(), 0); 438 view_->SetWindowTextAndCaretPos(std::wstring(), 0);
444 is_keyword_hint_ = false; 439 is_keyword_hint_ = false;
445 keyword_ui_state_ = KEYWORD;
446 view_->OnAfterPossibleChange(); 440 view_->OnAfterPossibleChange();
447 just_deleted_text_ = false; // OnAfterPossibleChange() erroneously sets this 441 just_deleted_text_ = false; // OnAfterPossibleChange() erroneously sets this
448 // since the edit contents have disappeared. It 442 // since the edit contents have disappeared. It
449 // doesn't really matter, but we clear it to be 443 // doesn't really matter, but we clear it to be
450 // consistent. 444 // consistent.
451 UserMetrics::RecordAction(UserMetricsAction("AcceptedKeywordHint"), profile_); 445 UserMetrics::RecordAction(UserMetricsAction("AcceptedKeywordHint"), profile_);
452 } 446 }
453 447
454 void AutocompleteEditModel::ClearKeyword(const std::wstring& visible_text) { 448 void AutocompleteEditModel::ClearKeyword(const std::wstring& visible_text) {
455 view_->OnBeforePossibleChange(); 449 view_->OnBeforePossibleChange();
456 const std::wstring window_text(keyword_ + visible_text); 450 const std::wstring window_text(keyword_ + visible_text);
457 view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length()); 451 view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length());
458 keyword_.clear(); 452 keyword_.clear();
459 keyword_ui_state_ = NORMAL; 453 is_keyword_hint_ = false;
460 view_->OnAfterPossibleChange(); 454 view_->OnAfterPossibleChange();
461 just_deleted_text_ = true; // OnAfterPossibleChange() fails to clear this 455 just_deleted_text_ = true; // OnAfterPossibleChange() fails to clear this
462 // since the edit contents have actually grown 456 // since the edit contents have actually grown
463 // longer. 457 // longer.
464 } 458 }
465 459
466 bool AutocompleteEditModel::query_in_progress() const { 460 bool AutocompleteEditModel::query_in_progress() const {
467 return !popup_->autocomplete_controller()->done(); 461 return !popup_->autocomplete_controller()->done();
468 } 462 }
469 463
(...skipping 25 matching lines...) Expand all
495 bool AutocompleteEditModel::OnEscapeKeyPressed() { 489 bool AutocompleteEditModel::OnEscapeKeyPressed() {
496 if (has_temporary_text_) { 490 if (has_temporary_text_) {
497 AutocompleteMatch match; 491 AutocompleteMatch match;
498 popup_->InfoForCurrentSelection(&match, NULL); 492 popup_->InfoForCurrentSelection(&match, NULL);
499 if (match.destination_url != original_url_) { 493 if (match.destination_url != original_url_) {
500 // The user typed something, then selected a different item. Restore the 494 // The user typed something, then selected a different item. Restore the
501 // text they typed and change back to the default item. 495 // text they typed and change back to the default item.
502 // NOTE: This purposefully does not reset paste_state_. 496 // NOTE: This purposefully does not reset paste_state_.
503 just_deleted_text_ = false; 497 just_deleted_text_ = false;
504 has_temporary_text_ = false; 498 has_temporary_text_ = false;
505 keyword_ui_state_ = original_keyword_ui_state_;
506 popup_->ResetToDefaultMatch(); 499 popup_->ResetToDefaultMatch();
507 view_->OnRevertTemporaryText(); 500 view_->OnRevertTemporaryText();
508 return true; 501 return true;
509 } 502 }
510 } 503 }
511 504
512 // If the user wasn't editing, but merely had focus in the edit, allow <esc> 505 // If the user wasn't editing, but merely had focus in the edit, allow <esc>
513 // to be processed as an accelerator, so it can still be used to stop a load. 506 // to be processed as an accelerator, so it can still be used to stop a load.
514 // When the permanent text isn't all selected we still fall through to the 507 // When the permanent text isn't all selected we still fall through to the
515 // SelectAll() call below so users can arrow around in the text and then hit 508 // SelectAll() call below so users can arrow around in the text and then hit
(...skipping 21 matching lines...) Expand all
537 } 530 }
538 if ((old_state != DOWN_WITH_CHANGE) && popup_->IsOpen()) { 531 if ((old_state != DOWN_WITH_CHANGE) && popup_->IsOpen()) {
539 // Autocomplete history provider results may change, so refresh the 532 // Autocomplete history provider results may change, so refresh the
540 // popup. This will force user_input_in_progress_ to true, but if the 533 // popup. This will force user_input_in_progress_ to true, but if the
541 // popup is open, that should have already been the case. 534 // popup is open, that should have already been the case.
542 view_->UpdatePopup(); 535 view_->UpdatePopup();
543 } 536 }
544 } 537 }
545 } 538 }
546 539
540 void AutocompleteEditModel::OnPaste(bool replacing_all) {
541 paste_state_ = replacing_all ? REPLACING_ALL : PASTING;
542 }
543
547 void AutocompleteEditModel::OnUpOrDownKeyPressed(int count) { 544 void AutocompleteEditModel::OnUpOrDownKeyPressed(int count) {
548 // NOTE: This purposefully don't trigger any code that resets paste_state_. 545 // NOTE: This purposefully don't trigger any code that resets paste_state_.
549 546
550 if (!popup_->IsOpen()) { 547 if (!popup_->IsOpen()) {
551 if (!query_in_progress()) { 548 if (!query_in_progress()) {
552 // The popup is neither open nor working on a query already. So, start an 549 // The popup is neither open nor working on a query already. So, start an
553 // autocomplete query for the current text. This also sets 550 // autocomplete query for the current text. This also sets
554 // user_input_in_progress_ to true, which we want: if the user has started 551 // user_input_in_progress_ to true, which we want: if the user has started
555 // to interact with the popup, changing the permanent_text_ shouldn't 552 // to interact with the popup, changing the permanent_text_ shouldn't
556 // change the displayed text. 553 // change the displayed text.
(...skipping 12 matching lines...) Expand all
569 // normally. 566 // normally.
570 popup_->Move(count); 567 popup_->Move(count);
571 } 568 }
572 } 569 }
573 570
574 void AutocompleteEditModel::OnPopupDataChanged( 571 void AutocompleteEditModel::OnPopupDataChanged(
575 const std::wstring& text, 572 const std::wstring& text,
576 GURL* destination_for_temporary_text_change, 573 GURL* destination_for_temporary_text_change,
577 const std::wstring& keyword, 574 const std::wstring& keyword,
578 bool is_keyword_hint) { 575 bool is_keyword_hint) {
579 KeywordUIState old_keyword_ui_state = keyword_ui_state_;
580
581 // Update keyword/hint-related local state. 576 // Update keyword/hint-related local state.
582 bool keyword_state_changed = (keyword_ != keyword) || 577 bool keyword_state_changed = (keyword_ != keyword) ||
583 ((is_keyword_hint_ != is_keyword_hint) && !keyword.empty()); 578 ((is_keyword_hint_ != is_keyword_hint) && !keyword.empty());
584 if (keyword_state_changed) { 579 if (keyword_state_changed) {
585 keyword_ = keyword; 580 keyword_ = keyword;
586 is_keyword_hint_ = is_keyword_hint; 581 is_keyword_hint_ = is_keyword_hint;
587 }
588 582
589 // Update |keyword_ui_state_| only when necessary. It may be changed even if 583 // |is_keyword_hint_| should always be false if |keyword_| is empty.
590 // |keyword_state_changed| is false. 584 DCHECK(!keyword_.empty() || !is_keyword_hint_);
591 if (keyword_ui_state_ != NO_KEYWORD) {
592 keyword_ui_state_ = (is_keyword_hint_ || keyword_.empty()) ?
593 NORMAL : KEYWORD;
594 } 585 }
595 586
596 // Handle changes to temporary text. 587 // Handle changes to temporary text.
597 if (destination_for_temporary_text_change != NULL) { 588 if (destination_for_temporary_text_change != NULL) {
598 const bool save_original_selection = !has_temporary_text_; 589 const bool save_original_selection = !has_temporary_text_;
599 if (save_original_selection) { 590 if (save_original_selection) {
600 // Save the original selection and URL so it can be reverted later. 591 // Save the original selection and URL so it can be reverted later.
601 has_temporary_text_ = true; 592 has_temporary_text_ = true;
602 original_url_ = *destination_for_temporary_text_change; 593 original_url_ = *destination_for_temporary_text_change;
603 original_keyword_ui_state_ = old_keyword_ui_state;
604 inline_autocomplete_text_.clear(); 594 inline_autocomplete_text_.clear();
605 } 595 }
606 if (control_key_state_ == DOWN_WITHOUT_CHANGE) { 596 if (control_key_state_ == DOWN_WITHOUT_CHANGE) {
607 // Arrowing around the popup cancels control-enter. 597 // Arrowing around the popup cancels control-enter.
608 control_key_state_ = DOWN_WITH_CHANGE; 598 control_key_state_ = DOWN_WITH_CHANGE;
609 // Now things are a bit screwy: the desired_tld has changed, but if we 599 // Now things are a bit screwy: the desired_tld has changed, but if we
610 // update the popup, the new order of entries won't match the old, so the 600 // update the popup, the new order of entries won't match the old, so the
611 // user's selection gets screwy; and if we don't update the popup, and the 601 // user's selection gets screwy; and if we don't update the popup, and the
612 // user reverts, then the selected item will be as if control is still 602 // user reverts, then the selected item will be as if control is still
613 // pressed, even though maybe it isn't any more. There is no obvious 603 // pressed, even though maybe it isn't any more. There is no obvious
(...skipping 24 matching lines...) Expand all
638 const std::wstring& new_text, 628 const std::wstring& new_text,
639 bool selection_differs, 629 bool selection_differs,
640 bool text_differs, 630 bool text_differs,
641 bool just_deleted_text, 631 bool just_deleted_text,
642 bool allow_keyword_ui_change) { 632 bool allow_keyword_ui_change) {
643 // Update the paste state as appropriate: if we're just finishing a paste 633 // Update the paste state as appropriate: if we're just finishing a paste
644 // that replaced all the text, preserve that information; otherwise, if we've 634 // that replaced all the text, preserve that information; otherwise, if we've
645 // made some other edit, clear paste tracking. 635 // made some other edit, clear paste tracking.
646 if (paste_state_ == REPLACING_ALL) 636 if (paste_state_ == REPLACING_ALL)
647 paste_state_ = REPLACED_ALL; 637 paste_state_ = REPLACED_ALL;
638 else if (paste_state_ == PASTING)
639 paste_state_ = PASTED;
648 else if (text_differs) 640 else if (text_differs)
649 paste_state_ = NONE; 641 paste_state_ = NONE;
650 642
651 // Modifying the selection counts as accepting the autocompleted text. 643 // Modifying the selection counts as accepting the autocompleted text.
652 const bool user_text_changed = 644 const bool user_text_changed =
653 text_differs || (selection_differs && !inline_autocomplete_text_.empty()); 645 text_differs || (selection_differs && !inline_autocomplete_text_.empty());
654 646
655 // If something has changed while the control key is down, prevent 647 // If something has changed while the control key is down, prevent
656 // "ctrl-enter" until the control key is released. When we do this, we need 648 // "ctrl-enter" until the control key is released. When we do this, we need
657 // to update the popup if it's open, since the desired_tld will have changed. 649 // to update the popup if it's open, since the desired_tld will have changed.
658 if ((text_differs || selection_differs) && 650 if ((text_differs || selection_differs) &&
659 (control_key_state_ == DOWN_WITHOUT_CHANGE)) { 651 (control_key_state_ == DOWN_WITHOUT_CHANGE)) {
660 control_key_state_ = DOWN_WITH_CHANGE; 652 control_key_state_ = DOWN_WITH_CHANGE;
661 if (!text_differs && !popup_->IsOpen()) 653 if (!text_differs && !popup_->IsOpen())
662 return false; // Don't open the popup for no reason. 654 return false; // Don't open the popup for no reason.
663 } else if (!user_text_changed) { 655 } else if (!user_text_changed) {
664 return false; 656 return false;
665 } 657 }
666 658
667 const bool had_keyword = KeywordIsSelected();
668
669 // If the user text has not changed, we do not want to change the model's 659 // If the user text has not changed, we do not want to change the model's
670 // state associated with the text. Otherwise, we can get surprising behavior 660 // state associated with the text. Otherwise, we can get surprising behavior
671 // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983 661 // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983
672 if (user_text_changed) { 662 if (user_text_changed) {
673 InternalSetUserText(UserTextFromDisplayText(new_text)); 663 const std::wstring new_user_text = UserTextFromDisplayText(new_text);
664
665 // Try to accept the current keyword if the user only typed a space at the
666 // end of content. Model's state and popup will be updated when the keyword
667 // is accepted. So we just need to return false here.
668 if (allow_keyword_ui_change && !selection_differs &&
669 MaybeAcceptKeywordBySpace(new_user_text))
670 return false;
671
672 InternalSetUserText(new_user_text);
674 has_temporary_text_ = false; 673 has_temporary_text_ = false;
675 674
676 // Track when the user has deleted text so we won't allow inline 675 // Track when the user has deleted text so we won't allow inline
677 // autocomplete. 676 // autocomplete.
678 just_deleted_text_ = just_deleted_text; 677 just_deleted_text_ = just_deleted_text;
679 } 678 }
680 679
681 // Disable the fancy keyword UI if the user didn't already have a visible
682 // keyword and the view doesn't want us to change the keyword UI state.
683 // This prevents us from showing the fancy UI and interrupting the user's
684 // editing if, for example, the user happens to have a keyword for 'a',
685 // types 'ab' then puts a space between the 'a' and the 'b'.
686 // If |keyword_ui_state_| is set to NORMAL here, then it will be updated
687 // to a proper value in OnPopupDataChanged() method according to the new
688 // match result.
689 if (!had_keyword)
690 keyword_ui_state_ = allow_keyword_ui_change ? NORMAL : NO_KEYWORD;
691
692 view_->UpdatePopup(); 680 view_->UpdatePopup();
693 return true; 681 return true;
694 } 682 }
695 683
696 void AutocompleteEditModel::PopupBoundsChangedTo(const gfx::Rect& bounds) { 684 void AutocompleteEditModel::PopupBoundsChangedTo(const gfx::Rect& bounds) {
697 controller_->OnPopupBoundsChanged(bounds); 685 controller_->OnPopupBoundsChanged(bounds);
698 } 686 }
699 687
700 void AutocompleteEditModel::ResultsUpdated() { 688 void AutocompleteEditModel::ResultsUpdated() {
701 UpdateSuggestedSearchText(); 689 UpdateSuggestedSearchText();
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
755 OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, is_keyword_hint); 743 OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, is_keyword_hint);
756 } 744 }
757 745
758 void AutocompleteEditModel::InternalSetUserText(const std::wstring& text) { 746 void AutocompleteEditModel::InternalSetUserText(const std::wstring& text) {
759 user_text_ = text; 747 user_text_ = text;
760 just_deleted_text_ = false; 748 just_deleted_text_ = false;
761 inline_autocomplete_text_.clear(); 749 inline_autocomplete_text_.clear();
762 } 750 }
763 751
764 bool AutocompleteEditModel::KeywordIsSelected() const { 752 bool AutocompleteEditModel::KeywordIsSelected() const {
765 return keyword_ui_state_ == KEYWORD; 753 return !is_keyword_hint_ && !keyword_.empty();
766 } 754 }
767 755
768 std::wstring AutocompleteEditModel::DisplayTextFromUserText( 756 std::wstring AutocompleteEditModel::DisplayTextFromUserText(
769 const std::wstring& text) const { 757 const std::wstring& text) const {
770 return KeywordIsSelected() ? 758 return KeywordIsSelected() ?
771 KeywordProvider::SplitReplacementStringFromInput(text, false) : text; 759 KeywordProvider::SplitReplacementStringFromInput(text, false) : text;
772 } 760 }
773 761
774 std::wstring AutocompleteEditModel::UserTextFromDisplayText( 762 std::wstring AutocompleteEditModel::UserTextFromDisplayText(
775 const std::wstring& text) const { 763 const std::wstring& text) const {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 i->inline_autocomplete_offset != std::wstring::npos) { 815 i->inline_autocomplete_offset != std::wstring::npos) {
828 suggested_text = WideToUTF16(i->fill_into_edit.substr( 816 suggested_text = WideToUTF16(i->fill_into_edit.substr(
829 i->inline_autocomplete_offset)); 817 i->inline_autocomplete_offset));
830 break; 818 break;
831 } 819 }
832 } 820 }
833 } 821 }
834 } 822 }
835 controller_->OnSetSuggestedSearchText(suggested_text); 823 controller_->OnSetSuggestedSearchText(suggested_text);
836 } 824 }
825
826 bool AutocompleteEditModel::MaybeAcceptKeywordBySpace(
827 const std::wstring& new_user_text) {
828 if (paste_state_ != NONE || !is_keyword_hint_ || keyword_.empty() ||
Peter Kasting 2011/01/20 00:04:22 Nit: This file puts parens around boolean subcondi
James Su 2011/01/20 06:49:31 Done with slightly different logic, because: 1. th
Peter Kasting 2011/01/20 18:49:23 That's why my find_first_of() call had a second ar
829 !inline_autocomplete_text_.empty())
830 return false;
831
832 const size_t old_length = user_text_.length();
833 const size_t new_length = new_user_text.length();
834 if (old_length && old_length + 1 == new_length &&
835 user_text_ == new_user_text.substr(0, old_length) &&
836 IsWhitespace(new_user_text[old_length]) &&
837 !IsWhitespace(user_text_[old_length - 1])) {
838 AcceptKeyword();
839 return true;
840 }
841 return false;
842 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698