Chromium Code Reviews| 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.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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } | |
| OLD | NEW |