OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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/views/omnibox/omnibox_view_views.h" | 5 #include "chrome/browser/ui/views/omnibox/omnibox_view_views.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
61 #include "ui/compositor/layer.h" | 61 #include "ui/compositor/layer.h" |
62 #endif | 62 #endif |
63 | 63 |
64 namespace { | 64 namespace { |
65 | 65 |
66 // Stores omnibox state for each tab. | 66 // Stores omnibox state for each tab. |
67 struct OmniboxState : public base::SupportsUserData::Data { | 67 struct OmniboxState : public base::SupportsUserData::Data { |
68 static const char kKey[]; | 68 static const char kKey[]; |
69 | 69 |
70 OmniboxState(const OmniboxEditModel::State& model_state, | 70 OmniboxState(const OmniboxEditModel::State& model_state, |
71 const gfx::SelectionModel& selection_model); | 71 const gfx::Range& selection, |
72 const gfx::Range& saved_selection_for_focus_change); | |
72 virtual ~OmniboxState(); | 73 virtual ~OmniboxState(); |
73 | 74 |
74 const OmniboxEditModel::State model_state; | 75 const OmniboxEditModel::State model_state; |
75 const gfx::SelectionModel selection_model; | 76 |
77 // We store both the actual selection and any saved selection (for when the | |
78 // omnibox is not focused). This allows us to properly handle cases like | |
79 // selecting text, tabbing out of the omnibox, switching tabs away and back, | |
80 // and tabbing back into the omnibox. | |
81 const gfx::Range selection; | |
82 const gfx::Range saved_selection_for_focus_change; | |
76 }; | 83 }; |
77 | 84 |
78 // static | 85 // static |
79 const char OmniboxState::kKey[] = "OmniboxState"; | 86 const char OmniboxState::kKey[] = "OmniboxState"; |
80 | 87 |
81 OmniboxState::OmniboxState(const OmniboxEditModel::State& model_state, | 88 OmniboxState::OmniboxState(const OmniboxEditModel::State& model_state, |
82 const gfx::SelectionModel& selection_model) | 89 const gfx::Range& selection, |
90 const gfx::Range& saved_selection_for_focus_change) | |
83 : model_state(model_state), | 91 : model_state(model_state), |
84 selection_model(selection_model) { | 92 selection(selection), |
93 saved_selection_for_focus_change(saved_selection_for_focus_change) { | |
85 } | 94 } |
86 | 95 |
87 OmniboxState::~OmniboxState() {} | 96 OmniboxState::~OmniboxState() {} |
88 | 97 |
89 // We'd like to set the text input type to TEXT_INPUT_TYPE_URL, because this | 98 // We'd like to set the text input type to TEXT_INPUT_TYPE_URL, because this |
90 // triggers URL-specific layout in software keyboards, e.g. adding top-level "/" | 99 // triggers URL-specific layout in software keyboards, e.g. adding top-level "/" |
91 // and ".com" keys for English. However, this also causes IMEs to default to | 100 // and ".com" keys for English. However, this also causes IMEs to default to |
92 // Latin character mode, which makes entering search queries difficult for IME | 101 // Latin character mode, which makes entering search queries difficult for IME |
93 // users. Therefore, we try to guess whether an IME will be used based on the | 102 // users. Therefore, we try to guess whether an IME will be used based on the |
94 // application language, and set the input type accordingly. | 103 // application language, and set the input type accordingly. |
(...skipping 27 matching lines...) Expand all Loading... | |
122 OmniboxViewViews::OmniboxViewViews(OmniboxEditController* controller, | 131 OmniboxViewViews::OmniboxViewViews(OmniboxEditController* controller, |
123 Profile* profile, | 132 Profile* profile, |
124 CommandUpdater* command_updater, | 133 CommandUpdater* command_updater, |
125 bool popup_window_mode, | 134 bool popup_window_mode, |
126 LocationBarView* location_bar, | 135 LocationBarView* location_bar, |
127 const gfx::FontList& font_list, | 136 const gfx::FontList& font_list, |
128 int font_y_offset) | 137 int font_y_offset) |
129 : OmniboxView(profile, controller, command_updater), | 138 : OmniboxView(profile, controller, command_updater), |
130 popup_window_mode_(popup_window_mode), | 139 popup_window_mode_(popup_window_mode), |
131 security_level_(ToolbarModel::NONE), | 140 security_level_(ToolbarModel::NONE), |
141 saved_selection_for_focus_change_(gfx::Range::InvalidRange()), | |
132 ime_composing_before_change_(false), | 142 ime_composing_before_change_(false), |
133 delete_at_end_pressed_(false), | 143 delete_at_end_pressed_(false), |
134 location_bar_view_(location_bar), | 144 location_bar_view_(location_bar), |
135 ime_candidate_window_open_(false), | 145 ime_candidate_window_open_(false), |
136 select_all_on_mouse_release_(false), | 146 select_all_on_mouse_release_(false), |
137 select_all_on_gesture_tap_(false) { | 147 select_all_on_gesture_tap_(false) { |
138 RemoveBorder(); | 148 RemoveBorder(); |
139 set_id(VIEW_ID_OMNIBOX); | 149 set_id(VIEW_ID_OMNIBOX); |
140 SetFontList(font_list); | 150 SetFontList(font_list); |
141 SetVerticalMargins(font_y_offset, 0); | 151 SetVerticalMargins(font_y_offset, 0); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
179 // OmniboxViewViews, views::Textfield implementation: | 189 // OmniboxViewViews, views::Textfield implementation: |
180 | 190 |
181 const char* OmniboxViewViews::GetClassName() const { | 191 const char* OmniboxViewViews::GetClassName() const { |
182 return kViewClassName; | 192 return kViewClassName; |
183 } | 193 } |
184 | 194 |
185 void OmniboxViewViews::OnGestureEvent(ui::GestureEvent* event) { | 195 void OmniboxViewViews::OnGestureEvent(ui::GestureEvent* event) { |
186 views::Textfield::OnGestureEvent(event); | 196 views::Textfield::OnGestureEvent(event); |
187 if (!HasFocus() && event->type() == ui::ET_GESTURE_TAP_DOWN) { | 197 if (!HasFocus() && event->type() == ui::ET_GESTURE_TAP_DOWN) { |
188 select_all_on_gesture_tap_ = true; | 198 select_all_on_gesture_tap_ = true; |
199 | |
200 // If we're trying to select all on tap, invalidate any saved selection lest | |
201 // restoring it fight with the "select all" action. | |
msw
2013/09/21 00:43:11
nit: "fights" I guess.
| |
202 saved_selection_for_focus_change_ = gfx::Range::InvalidRange(); | |
189 return; | 203 return; |
190 } | 204 } |
191 if (select_all_on_gesture_tap_ && event->type() == ui::ET_GESTURE_TAP) | 205 if (select_all_on_gesture_tap_ && event->type() == ui::ET_GESTURE_TAP) |
192 SelectAll(false); | 206 SelectAll(false); |
193 select_all_on_gesture_tap_ = false; | 207 select_all_on_gesture_tap_ = false; |
194 } | 208 } |
195 | 209 |
196 void OmniboxViewViews::GetAccessibleState(ui::AccessibleViewState* state) { | 210 void OmniboxViewViews::GetAccessibleState(ui::AccessibleViewState* state) { |
197 location_bar_view_->GetAccessibleState(state); | 211 location_bar_view_->GetAccessibleState(state); |
198 state->role = ui::AccessibilityTypes::ROLE_TEXT; | 212 state->role = ui::AccessibilityTypes::ROLE_TEXT; |
199 } | 213 } |
200 | 214 |
201 bool OmniboxViewViews::OnMousePressed(const ui::MouseEvent& event) { | 215 bool OmniboxViewViews::OnMousePressed(const ui::MouseEvent& event) { |
202 select_all_on_mouse_release_ = | 216 select_all_on_mouse_release_ = |
203 (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) && | 217 (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) && |
204 (!HasFocus() || (model()->focus_state() == OMNIBOX_FOCUS_INVISIBLE)); | 218 (!HasFocus() || (model()->focus_state() == OMNIBOX_FOCUS_INVISIBLE)); |
205 // Restore caret visibility whenever the user clicks in the omnibox in a way | 219 if (select_all_on_mouse_release_) { |
206 // that would give it focus. We must handle this case separately here because | 220 // Restore caret visibility whenever the user clicks in the omnibox in a way |
207 // if the omnibox currently has invisible focus, the mouse event won't trigger | 221 // that would give it focus. We must handle this case separately here |
208 // either SetFocus() or OmniboxEditModel::OnSetFocus(). | 222 // because if the omnibox currently has invisible focus, the mouse event |
209 if (select_all_on_mouse_release_) | 223 // won't trigger either SetFocus() or OmniboxEditModel::OnSetFocus(). |
210 model()->SetCaretVisibility(true); | 224 model()->SetCaretVisibility(true); |
225 | |
226 // When we're going to select all on mouse release, invalidate any saved | |
227 // selection lest restoring it fight with the "select all" action. It's | |
msw
2013/09/21 00:43:11
nit: "fights" I guess.
| |
228 // possible to later set select_all_on_mouse_release_ back to false, but | |
229 // that happens for things like dragging, which are cases where having | |
230 // invalidated this saved selection is still OK. | |
231 saved_selection_for_focus_change_ = gfx::Range::InvalidRange(); | |
232 } | |
211 return views::Textfield::OnMousePressed(event); | 233 return views::Textfield::OnMousePressed(event); |
212 } | 234 } |
213 | 235 |
214 bool OmniboxViewViews::OnMouseDragged(const ui::MouseEvent& event) { | 236 bool OmniboxViewViews::OnMouseDragged(const ui::MouseEvent& event) { |
215 select_all_on_mouse_release_ = false; | 237 select_all_on_mouse_release_ = false; |
216 return views::Textfield::OnMouseDragged(event); | 238 return views::Textfield::OnMouseDragged(event); |
217 } | 239 } |
218 | 240 |
219 void OmniboxViewViews::OnMouseReleased(const ui::MouseEvent& event) { | 241 void OmniboxViewViews::OnMouseReleased(const ui::MouseEvent& event) { |
220 views::Textfield::OnMouseReleased(event); | 242 views::Textfield::OnMouseReleased(event); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
322 | 344 |
323 return Textfield::SkipDefaultKeyEventProcessing(event); | 345 return Textfield::SkipDefaultKeyEventProcessing(event); |
324 } | 346 } |
325 | 347 |
326 void OmniboxViewViews::OnFocus() { | 348 void OmniboxViewViews::OnFocus() { |
327 views::Textfield::OnFocus(); | 349 views::Textfield::OnFocus(); |
328 // TODO(oshima): Get control key state. | 350 // TODO(oshima): Get control key state. |
329 model()->OnSetFocus(false); | 351 model()->OnSetFocus(false); |
330 // Don't call controller()->OnSetFocus, this view has already acquired focus. | 352 // Don't call controller()->OnSetFocus, this view has already acquired focus. |
331 | 353 |
332 // Restore a valid saved selection on tab-to-focus. | 354 // Restore the selection we saved in OnBlur() if it's still valid. |
333 if (location_bar_view_->GetWebContents() && !select_all_on_mouse_release_) { | 355 if (saved_selection_for_focus_change_.IsValid()) { |
334 const OmniboxState* state = static_cast<OmniboxState*>( | 356 SelectRange(saved_selection_for_focus_change_); |
335 location_bar_view_->GetWebContents()->GetUserData(&OmniboxState::kKey)); | 357 saved_selection_for_focus_change_ = gfx::Range::InvalidRange(); |
336 if (state) | |
337 SelectSelectionModel(state->selection_model); | |
338 } | 358 } |
339 } | 359 } |
340 | 360 |
341 void OmniboxViewViews::OnBlur() { | 361 void OmniboxViewViews::OnBlur() { |
342 // Save the selection to restore on tab-to-focus. | 362 // Save the user's existing selection to restore it later. |
343 if (location_bar_view_->GetWebContents()) | 363 saved_selection_for_focus_change_ = GetSelectedRange(); |
344 SaveStateToTab(location_bar_view_->GetWebContents()); | |
345 | 364 |
346 views::Textfield::OnBlur(); | 365 views::Textfield::OnBlur(); |
347 gfx::NativeView native_view = NULL; | 366 gfx::NativeView native_view = NULL; |
348 #if defined(USE_AURA) | 367 #if defined(USE_AURA) |
349 views::Widget* widget = GetWidget(); | 368 views::Widget* widget = GetWidget(); |
350 if (widget) { | 369 if (widget) { |
351 aura::client::FocusClient* client = | 370 aura::client::FocusClient* client = |
352 aura::client::GetFocusClient(widget->GetNativeView()); | 371 aura::client::GetFocusClient(widget->GetNativeView()); |
353 if (client) | 372 if (client) |
354 native_view = client->GetFocusedWindow(); | 373 native_view = client->GetFocusedWindow(); |
355 } | 374 } |
356 #endif | 375 #endif |
357 model()->OnWillKillFocus(native_view); | 376 model()->OnWillKillFocus(native_view); |
358 // Close the popup. | 377 // Close the popup. |
359 CloseOmniboxPopup(); | 378 CloseOmniboxPopup(); |
379 | |
360 // Tell the model to reset itself. | 380 // Tell the model to reset itself. |
361 model()->OnKillFocus(); | 381 model()->OnKillFocus(); |
362 controller()->OnKillFocus(); | 382 controller()->OnKillFocus(); |
363 | 383 |
364 // Make sure the beginning of the text is visible. | 384 // Make sure the beginning of the text is visible. |
365 SelectRange(gfx::Range(0)); | 385 SelectRange(gfx::Range(0)); |
366 } | 386 } |
367 | 387 |
368 //////////////////////////////////////////////////////////////////////////////// | 388 //////////////////////////////////////////////////////////////////////////////// |
369 // OmniboxViewViews, OmniboxView implementation: | 389 // OmniboxViewViews, OmniboxView implementation: |
370 | 390 |
371 void OmniboxViewViews::SaveStateToTab(content::WebContents* tab) { | 391 void OmniboxViewViews::SaveStateToTab(content::WebContents* tab) { |
372 DCHECK(tab); | 392 DCHECK(tab); |
373 | 393 |
374 // We don't want to keep the IME status, so force quit the current | 394 // We don't want to keep the IME status, so force quit the current |
375 // session here. It may affect the selection status, so order is | 395 // session here. It may affect the selection status, so order is |
376 // also important. | 396 // also important. |
377 if (IsIMEComposing()) { | 397 if (IsIMEComposing()) { |
378 GetTextInputClient()->ConfirmCompositionText(); | 398 GetTextInputClient()->ConfirmCompositionText(); |
379 GetInputMethod()->CancelComposition(this); | 399 GetInputMethod()->CancelComposition(this); |
380 } | 400 } |
381 | 401 |
382 // NOTE: GetStateForTabSwitch may affect GetSelection, so order is important. | 402 // NOTE: GetStateForTabSwitch() may affect GetSelectedRange(), so order is |
403 // important. | |
383 OmniboxEditModel::State state = model()->GetStateForTabSwitch(); | 404 OmniboxEditModel::State state = model()->GetStateForTabSwitch(); |
384 const gfx::SelectionModel selection = GetSelectionModel(); | 405 tab->SetUserData(OmniboxState::kKey, new OmniboxState( |
385 tab->SetUserData(OmniboxState::kKey, new OmniboxState(state, selection)); | 406 state, GetSelectedRange(), saved_selection_for_focus_change_)); |
386 } | 407 } |
387 | 408 |
388 void OmniboxViewViews::OnTabChanged(const content::WebContents* web_contents) { | 409 void OmniboxViewViews::OnTabChanged(const content::WebContents* web_contents) { |
389 security_level_ = controller()->GetToolbarModel()->GetSecurityLevel(false); | 410 security_level_ = controller()->GetToolbarModel()->GetSecurityLevel(false); |
390 | 411 |
391 const OmniboxState* state = static_cast<OmniboxState*>( | 412 const OmniboxState* state = static_cast<OmniboxState*>( |
392 web_contents->GetUserData(&OmniboxState::kKey)); | 413 web_contents->GetUserData(&OmniboxState::kKey)); |
393 model()->RestoreState(state ? &state->model_state : NULL); | 414 model()->RestoreState(state ? &state->model_state : NULL); |
394 if (state) | 415 if (state) { |
395 SelectSelectionModel(state->selection_model); | 416 // This assumes that the omnibox has already been focused or blurred as |
417 // appropriate; otherwise, a subsequent OnFocus() or OnBlur() call could | |
418 // goof up the selection. See comments at the end of | |
419 // BrowserView::ActiveTabChanged(). | |
420 SelectRange(state->selection); | |
421 saved_selection_for_focus_change_ = state->saved_selection_for_focus_change; | |
422 } | |
396 | 423 |
397 // TODO(msw|oshima): Consider saving/restoring edit history. | 424 // TODO(msw|oshima): Consider saving/restoring edit history. |
398 ClearEditHistory(); | 425 ClearEditHistory(); |
399 } | 426 } |
400 | 427 |
401 void OmniboxViewViews::Update() { | 428 void OmniboxViewViews::Update() { |
402 const ToolbarModel::SecurityLevel old_security_level = security_level_; | 429 const ToolbarModel::SecurityLevel old_security_level = security_level_; |
403 security_level_ = controller()->GetToolbarModel()->GetSecurityLevel(false); | 430 security_level_ = controller()->GetToolbarModel()->GetSecurityLevel(false); |
404 if (model()->UpdatePermanentText()) { | 431 if (model()->UpdatePermanentText()) { |
405 // Something visibly changed. Re-enable search term replacement. | 432 // Something visibly changed. Re-enable search term replacement. |
(...skipping 23 matching lines...) Expand all Loading... | |
429 } else if (old_security_level != security_level_) { | 456 } else if (old_security_level != security_level_) { |
430 EmphasizeURLComponents(); | 457 EmphasizeURLComponents(); |
431 } | 458 } |
432 } | 459 } |
433 | 460 |
434 string16 OmniboxViewViews::GetText() const { | 461 string16 OmniboxViewViews::GetText() const { |
435 // TODO(oshima): IME support | 462 // TODO(oshima): IME support |
436 return text(); | 463 return text(); |
437 } | 464 } |
438 | 465 |
466 void OmniboxViewViews::SetUserText(const string16& text, | |
467 const string16& display_text, | |
468 bool update_popup) { | |
469 saved_selection_for_focus_change_ = gfx::Range::InvalidRange(); | |
470 OmniboxView::SetUserText(text, display_text, update_popup); | |
471 } | |
472 | |
439 void OmniboxViewViews::SetWindowTextAndCaretPos(const string16& text, | 473 void OmniboxViewViews::SetWindowTextAndCaretPos(const string16& text, |
440 size_t caret_pos, | 474 size_t caret_pos, |
441 bool update_popup, | 475 bool update_popup, |
442 bool notify_text_changed) { | 476 bool notify_text_changed) { |
443 const gfx::Range range(caret_pos, caret_pos); | 477 const gfx::Range range(caret_pos, caret_pos); |
444 SetTextAndSelectedRange(text, range); | 478 SetTextAndSelectedRange(text, range); |
445 | 479 |
446 if (update_popup) | 480 if (update_popup) |
447 UpdatePopup(); | 481 UpdatePopup(); |
448 | 482 |
449 if (notify_text_changed) | 483 if (notify_text_changed) |
450 TextChanged(); | 484 TextChanged(); |
451 } | 485 } |
452 | 486 |
453 void OmniboxViewViews::SetForcedQuery() { | 487 void OmniboxViewViews::SetForcedQuery() { |
454 const string16 current_text(text()); | 488 const string16 current_text(text()); |
455 const size_t start = current_text.find_first_not_of(kWhitespaceUTF16); | 489 const size_t start = current_text.find_first_not_of(kWhitespaceUTF16); |
456 if (start == string16::npos || (current_text[start] != '?')) | 490 if (start == string16::npos || (current_text[start] != '?')) |
457 SetUserText(ASCIIToUTF16("?")); | 491 OmniboxView::SetUserText(ASCIIToUTF16("?")); |
458 else | 492 else |
459 SelectRange(gfx::Range(current_text.size(), start + 1)); | 493 SelectRange(gfx::Range(current_text.size(), start + 1)); |
460 } | 494 } |
461 | 495 |
462 bool OmniboxViewViews::IsSelectAll() const { | 496 bool OmniboxViewViews::IsSelectAll() const { |
463 // TODO(oshima): IME support. | 497 // TODO(oshima): IME support. |
464 return text() == GetSelectedText(); | 498 return text() == GetSelectedText(); |
465 } | 499 } |
466 | 500 |
467 bool OmniboxViewViews::DeleteAtEndPressed() { | 501 bool OmniboxViewViews::DeleteAtEndPressed() { |
468 return delete_at_end_pressed_; | 502 return delete_at_end_pressed_; |
469 } | 503 } |
470 | 504 |
471 void OmniboxViewViews::GetSelectionBounds(string16::size_type* start, | 505 void OmniboxViewViews::GetSelectionBounds(string16::size_type* start, |
472 string16::size_type* end) const { | 506 string16::size_type* end) const { |
473 const gfx::Range range = GetSelectedRange(); | 507 const gfx::Range range = GetSelectedRange(); |
474 *start = static_cast<size_t>(range.start()); | 508 *start = static_cast<size_t>(range.start()); |
475 *end = static_cast<size_t>(range.end()); | 509 *end = static_cast<size_t>(range.end()); |
476 } | 510 } |
477 | 511 |
478 void OmniboxViewViews::SelectAll(bool reversed) { | 512 void OmniboxViewViews::SelectAll(bool reversed) { |
479 views::Textfield::SelectAll(reversed); | 513 views::Textfield::SelectAll(reversed); |
480 } | 514 } |
481 | 515 |
516 void OmniboxViewViews::RevertAll() { | |
517 saved_selection_for_focus_change_ = gfx::Range::InvalidRange(); | |
518 OmniboxView::RevertAll(); | |
519 } | |
520 | |
482 void OmniboxViewViews::UpdatePopup() { | 521 void OmniboxViewViews::UpdatePopup() { |
483 model()->SetInputInProgress(true); | 522 model()->SetInputInProgress(true); |
484 if (!model()->has_focus()) | 523 if (!model()->has_focus()) |
485 return; | 524 return; |
486 | 525 |
487 // Hide the inline autocompletion for IME users. | 526 // Hide the inline autocompletion for IME users. |
488 location_bar_view_->SetImeInlineAutocompletion(string16()); | 527 location_bar_view_->SetImeInlineAutocompletion(string16()); |
489 | 528 |
490 // Prevent inline autocomplete when the caret isn't at the end of the text, | 529 // Prevent inline autocomplete when the caret isn't at the end of the text, |
491 // and during IME composition editing unless | 530 // and during IME composition editing unless |
(...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
920 const string16 text(GetClipboardText()); | 959 const string16 text(GetClipboardText()); |
921 if (!text.empty()) { | 960 if (!text.empty()) { |
922 // Record this paste, so we can do different behavior. | 961 // Record this paste, so we can do different behavior. |
923 model()->on_paste(); | 962 model()->on_paste(); |
924 // Force a Paste operation to trigger the text_changed code in | 963 // Force a Paste operation to trigger the text_changed code in |
925 // OnAfterPossibleChange(), even if identical contents are pasted. | 964 // OnAfterPossibleChange(), even if identical contents are pasted. |
926 text_before_change_.clear(); | 965 text_before_change_.clear(); |
927 InsertOrReplaceText(text); | 966 InsertOrReplaceText(text); |
928 } | 967 } |
929 } | 968 } |
OLD | NEW |