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); |
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)) | |
Peter Kasting
2011/01/14 00:43:31
I think that rather than trying to detect this cas
James Su
2011/01/14 01:03:54
The difference between Tab and Space is that Tab d
Peter Kasting
2011/01/14 01:20:01
This is part of why I suggested changing the under
James Su
2011/01/14 02:02:46
The problem is, the IME will handle the space key
Peter Kasting
2011/01/14 02:30:36
It seems like I don't understand how IMEs work wel
James Su
2011/01/14 03:26:22
There is no way on Windows to intercept a key even
Peter Kasting
2011/01/14 17:31:33
I've been reading a few MSDN docs and I don't thin
James Su
2011/01/14 18:04:12
Yes exactly. But if the user uses an IME and enabl
Peter Kasting
2011/01/19 19:24:42
It seems like acting directly on VK_SPACE might be
James Su
2011/01/19 19:57:15
One possible case is that an IME may use a differe
Peter Kasting
2011/01/19 20:07:05
We should not trigger keyword mode for this case.
| |
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() || | |
829 !controller_->IsKeywordHintVisible()) | |
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 |