| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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/ui/omnibox/omnibox_edit_model.h" | 5 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/auto_reset.h" | 10 #include "base/auto_reset.h" |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 base::string16* text, | 456 base::string16* text, |
| 457 GURL* url, | 457 GURL* url, |
| 458 bool* write_url) { | 458 bool* write_url) { |
| 459 *write_url = false; | 459 *write_url = false; |
| 460 | 460 |
| 461 // Do not adjust if selection did not start at the beginning of the field, or | 461 // Do not adjust if selection did not start at the beginning of the field, or |
| 462 // if the URL was omitted. | 462 // if the URL was omitted. |
| 463 if ((sel_min != 0) || controller_->GetToolbarModel()->WouldReplaceURL()) | 463 if ((sel_min != 0) || controller_->GetToolbarModel()->WouldReplaceURL()) |
| 464 return; | 464 return; |
| 465 | 465 |
| 466 if (!user_input_in_progress_ && is_all_selected) { | 466 // Check whether the user is trying to copy the current page's URL by |
| 467 // The user selected all the text and has not edited it. Use the url as the | 467 // selecting the whole thing without editing it. |
| 468 // text so that if the scheme was stripped it's added back, and the url | 468 // |
| 469 // is unescaped (we escape parts of the url for display). | 469 // This is complicated by ZeroSuggest. When ZeroSuggest is active, the user |
| 470 // may be selecting different items and thus changing the address bar text, |
| 471 // even though !user_input_in_progress_; and the permanent URL may change |
| 472 // without updating the visible text, just like when user input is in |
| 473 // progress. In these cases, we don't want to copy the underlying URL, we |
| 474 // want to copy what the user actually sees. However, if we simply never do |
| 475 // this block when !popup_model()->IsOpen(), then just clicking into the |
| 476 // address bar and trying to copy will always bypass this block on pages that |
| 477 // trigger ZeroSuggest, which is too conservative. Instead, in the |
| 478 // ZeroSuggest case, we check that (a) the user hasn't selected one of the |
| 479 // other suggestions, and (b) the selected text is still the same as the |
| 480 // permanent text. ((b) probably implies (a), but it doesn't hurt to be |
| 481 // sure.) If these hold, then it's safe to copy the underlying URL. |
| 482 if (!user_input_in_progress_ && is_all_selected && |
| 483 (!popup_model() || !popup_model()->IsOpen() || |
| 484 ((popup_model()->selected_line() == 0) && (*text == permanent_text_)))) { |
| 485 // It's safe to copy the underlying URL. These lines ensure that if the |
| 486 // scheme was stripped it's added back, and the URL is unescaped (we escape |
| 487 // parts of it for display). |
| 470 *url = PermanentURL(); | 488 *url = PermanentURL(); |
| 471 *text = base::UTF8ToUTF16(url->spec()); | 489 *text = base::UTF8ToUTF16(url->spec()); |
| 472 *write_url = true; | 490 *write_url = true; |
| 473 return; | 491 return; |
| 474 } | 492 } |
| 475 | 493 |
| 476 // We can't use CurrentTextIsURL() or GetDataForURLExport() because right now | 494 // We can't use CurrentTextIsURL() or GetDataForURLExport() because right now |
| 477 // the user is probably holding down control to cause the copy, which will | 495 // the user is probably holding down control to cause the copy, which will |
| 478 // screw up our calculation of the desired_tld. | 496 // screw up our calculation of the desired_tld. |
| 479 AutocompleteMatch match; | 497 AutocompleteMatch match; |
| (...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 978 delegate_->OnInputStateChanged(); | 996 delegate_->OnInputStateChanged(); |
| 979 } | 997 } |
| 980 | 998 |
| 981 void OmniboxEditModel::OnKillFocus() { | 999 void OmniboxEditModel::OnKillFocus() { |
| 982 SetFocusState(OMNIBOX_FOCUS_NONE, OMNIBOX_FOCUS_CHANGE_EXPLICIT); | 1000 SetFocusState(OMNIBOX_FOCUS_NONE, OMNIBOX_FOCUS_CHANGE_EXPLICIT); |
| 983 focus_source_ = INVALID; | 1001 focus_source_ = INVALID; |
| 984 control_key_state_ = UP; | 1002 control_key_state_ = UP; |
| 985 paste_state_ = NONE; | 1003 paste_state_ = NONE; |
| 986 } | 1004 } |
| 987 | 1005 |
| 1006 bool OmniboxEditModel::WillHandleEscapeKey() const { |
| 1007 return user_input_in_progress_ || |
| 1008 (has_temporary_text_ && |
| 1009 (CurrentMatch(NULL).destination_url != original_url_)); |
| 1010 } |
| 1011 |
| 988 bool OmniboxEditModel::OnEscapeKeyPressed() { | 1012 bool OmniboxEditModel::OnEscapeKeyPressed() { |
| 989 const AutocompleteMatch& match = CurrentMatch(NULL); | 1013 if (has_temporary_text_ && |
| 990 if (has_temporary_text_) { | 1014 (CurrentMatch(NULL).destination_url != original_url_)) { |
| 991 if (match.destination_url != original_url_) { | 1015 RevertTemporaryText(true); |
| 992 RevertTemporaryText(true); | 1016 return true; |
| 993 return true; | |
| 994 } | |
| 995 } | 1017 } |
| 996 | 1018 |
| 997 // We do not clear the pending entry from the omnibox when a load is first | 1019 // We do not clear the pending entry from the omnibox when a load is first |
| 998 // stopped. If the user presses Escape while stopped, we clear it. | 1020 // stopped. If the user presses Escape while stopped, whether editing or not, |
| 1021 // we clear it. |
| 999 if (delegate_->CurrentPageExists() && !delegate_->IsLoading()) { | 1022 if (delegate_->CurrentPageExists() && !delegate_->IsLoading()) { |
| 1000 delegate_->GetNavigationController().DiscardNonCommittedEntries(); | 1023 delegate_->GetNavigationController().DiscardNonCommittedEntries(); |
| 1001 view_->Update(); | 1024 view_->Update(); |
| 1002 } | 1025 } |
| 1003 | 1026 |
| 1004 // If the user wasn't editing, but merely had focus in the edit, allow <esc> | |
| 1005 // to be processed as an accelerator, so it can still be used to stop a load. | |
| 1006 // When the permanent text isn't all selected we still fall through to the | |
| 1007 // SelectAll() call below so users can arrow around in the text and then hit | |
| 1008 // <esc> to quickly replace all the text; this matches IE. | |
| 1009 const bool has_zero_suggest_match = match.provider && | |
| 1010 (match.provider->type() == AutocompleteProvider::TYPE_ZERO_SUGGEST); | |
| 1011 if (!has_zero_suggest_match && !user_input_in_progress_ && | |
| 1012 view_->IsSelectAll()) | |
| 1013 return false; | |
| 1014 | |
| 1015 if (!user_text_.empty()) { | 1027 if (!user_text_.empty()) { |
| 1016 UMA_HISTOGRAM_ENUMERATION(kOmniboxUserTextClearedHistogram, | 1028 UMA_HISTOGRAM_ENUMERATION(kOmniboxUserTextClearedHistogram, |
| 1017 OMNIBOX_USER_TEXT_CLEARED_WITH_ESCAPE, | 1029 OMNIBOX_USER_TEXT_CLEARED_WITH_ESCAPE, |
| 1018 OMNIBOX_USER_TEXT_CLEARED_NUM_OF_ITEMS); | 1030 OMNIBOX_USER_TEXT_CLEARED_NUM_OF_ITEMS); |
| 1019 } | 1031 } |
| 1020 | 1032 |
| 1033 // Unconditionally revert/select all. This ensures any popup, whether due to |
| 1034 // normal editing or ZeroSuggest, is closed, and the full text is selected. |
| 1035 // This in turn allows the user to use escape to quickly select all the text |
| 1036 // for ease of replacement, and matches other browsers. |
| 1037 bool user_input_was_in_progress = user_input_in_progress_; |
| 1021 view_->RevertAll(); | 1038 view_->RevertAll(); |
| 1022 view_->SelectAll(true); | 1039 view_->SelectAll(true); |
| 1023 return true; | 1040 |
| 1041 // If the user was in the midst of editing, don't cancel any underlying page |
| 1042 // load. This doesn't match IE or Firefox, but seems more correct. Note that |
| 1043 // we do allow the page load to be stopped in the case where ZeroSuggest was |
| 1044 // visible; this is so that it's still possible to focus the address bar and |
| 1045 // hit escape once to stop a load even if the address being loaded triggers |
| 1046 // the ZeroSuggest popup. |
| 1047 return user_input_was_in_progress; |
| 1024 } | 1048 } |
| 1025 | 1049 |
| 1026 void OmniboxEditModel::OnControlKeyChanged(bool pressed) { | 1050 void OmniboxEditModel::OnControlKeyChanged(bool pressed) { |
| 1027 if (pressed == (control_key_state_ == UP)) | 1051 if (pressed == (control_key_state_ == UP)) |
| 1028 control_key_state_ = pressed ? DOWN_WITHOUT_CHANGE : UP; | 1052 control_key_state_ = pressed ? DOWN_WITHOUT_CHANGE : UP; |
| 1029 } | 1053 } |
| 1030 | 1054 |
| 1031 void OmniboxEditModel::OnPaste() { | 1055 void OmniboxEditModel::OnPaste() { |
| 1032 UMA_HISTOGRAM_COUNTS("Omnibox.Paste", 1); | 1056 UMA_HISTOGRAM_COUNTS("Omnibox.Paste", 1); |
| 1033 paste_state_ = PASTING; | 1057 paste_state_ = PASTING; |
| (...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1469 // Update state and notify view if the omnibox has focus and the caret | 1493 // Update state and notify view if the omnibox has focus and the caret |
| 1470 // visibility changed. | 1494 // visibility changed. |
| 1471 const bool was_caret_visible = is_caret_visible(); | 1495 const bool was_caret_visible = is_caret_visible(); |
| 1472 focus_state_ = state; | 1496 focus_state_ = state; |
| 1473 if (focus_state_ != OMNIBOX_FOCUS_NONE && | 1497 if (focus_state_ != OMNIBOX_FOCUS_NONE && |
| 1474 is_caret_visible() != was_caret_visible) | 1498 is_caret_visible() != was_caret_visible) |
| 1475 view_->ApplyCaretVisibility(); | 1499 view_->ApplyCaretVisibility(); |
| 1476 | 1500 |
| 1477 delegate_->OnFocusChanged(focus_state_, reason); | 1501 delegate_->OnFocusChanged(focus_state_, reason); |
| 1478 } | 1502 } |
| OLD | NEW |