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_view_views.h" | 5 #include "chrome/browser/autocomplete/autocomplete_edit_view_views.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
10 #include "chrome/app/chrome_command_ids.h" | 10 #include "chrome/app/chrome_command_ids.h" |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 CommandUpdater* command_updater, | 114 CommandUpdater* command_updater, |
115 bool popup_window_mode, | 115 bool popup_window_mode, |
116 const views::View* location_bar) | 116 const views::View* location_bar) |
117 : model_(new AutocompleteEditModel(this, controller, profile)), | 117 : model_(new AutocompleteEditModel(this, controller, profile)), |
118 popup_view_(CreatePopupView(profile, location_bar)), | 118 popup_view_(CreatePopupView(profile, location_bar)), |
119 controller_(controller), | 119 controller_(controller), |
120 toolbar_model_(toolbar_model), | 120 toolbar_model_(toolbar_model), |
121 command_updater_(command_updater), | 121 command_updater_(command_updater), |
122 popup_window_mode_(popup_window_mode), | 122 popup_window_mode_(popup_window_mode), |
123 security_level_(ToolbarModel::NONE), | 123 security_level_(ToolbarModel::NONE), |
124 delete_was_pressed_(false), | 124 ime_composing_before_change_(false), |
125 delete_at_end_pressed_(false) { | 125 delete_at_end_pressed_(false) { |
126 set_border(views::Border::CreateEmptyBorder(kAutocompleteVerticalMargin, 0, | 126 set_border(views::Border::CreateEmptyBorder(kAutocompleteVerticalMargin, 0, |
127 kAutocompleteVerticalMargin, 0)); | 127 kAutocompleteVerticalMargin, 0)); |
128 } | 128 } |
129 | 129 |
130 AutocompleteEditViewViews::~AutocompleteEditViewViews() { | 130 AutocompleteEditViewViews::~AutocompleteEditViewViews() { |
131 NotificationService::current()->Notify( | 131 NotificationService::current()->Notify( |
132 NotificationType::AUTOCOMPLETE_EDIT_DESTROYED, | 132 NotificationType::AUTOCOMPLETE_EDIT_DESTROYED, |
133 Source<AutocompleteEditViewViews>(this), | 133 Source<AutocompleteEditViewViews>(this), |
134 NotificationService::NoDetails()); | 134 NotificationService::NoDetails()); |
(...skipping 22 matching lines...) Expand all Loading... |
157 } | 157 } |
158 | 158 |
159 void AutocompleteEditViewViews::SetBaseColor() { | 159 void AutocompleteEditViewViews::SetBaseColor() { |
160 // TODO(oshima): Implment style change. | 160 // TODO(oshima): Implment style change. |
161 NOTIMPLEMENTED(); | 161 NOTIMPLEMENTED(); |
162 } | 162 } |
163 | 163 |
164 bool AutocompleteEditViewViews::HandleAfterKeyEvent( | 164 bool AutocompleteEditViewViews::HandleAfterKeyEvent( |
165 const views::KeyEvent& event, | 165 const views::KeyEvent& event, |
166 bool handled) { | 166 bool handled) { |
167 handling_key_press_ = false; | |
168 if (content_maybe_changed_by_key_press_) | |
169 OnAfterPossibleChange(); | |
170 | |
171 if (event.key_code() == ui::VKEY_RETURN) { | 167 if (event.key_code() == ui::VKEY_RETURN) { |
172 bool alt_held = event.IsAltDown(); | 168 bool alt_held = event.IsAltDown(); |
173 model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false); | 169 model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false); |
174 handled = true; | 170 handled = true; |
175 } else if (!handled && event.key_code() == ui::VKEY_ESCAPE) { | 171 } else if (!handled && event.key_code() == ui::VKEY_ESCAPE) { |
176 // We can handle the Escape key if textfield did not handle it. | 172 // We can handle the Escape key if textfield did not handle it. |
177 // If it's not handled by us, then we need to propagate it up to the parent | 173 // If it's not handled by us, then we need to propagate it up to the parent |
178 // widgets, so that Escape accelerator can still work. | 174 // widgets, so that Escape accelerator can still work. |
179 handled = model_->OnEscapeKeyPressed(); | 175 handled = model_->OnEscapeKeyPressed(); |
180 } else if (event.key_code() == ui::VKEY_CONTROL) { | 176 } else if (event.key_code() == ui::VKEY_CONTROL) { |
181 // Omnibox2 can switch its contents while pressing a control key. To switch | 177 // Omnibox2 can switch its contents while pressing a control key. To switch |
182 // the contents of omnibox2, we notify the AutocompleteEditModel class when | 178 // the contents of omnibox2, we notify the AutocompleteEditModel class when |
183 // the control-key state is changed. | 179 // the control-key state is changed. |
184 model_->OnControlKeyChanged(true); | 180 model_->OnControlKeyChanged(true); |
185 } else if (!text_changed_ && event.key_code() == ui::VKEY_DELETE && | 181 } else if (!handled && event.key_code() == ui::VKEY_DELETE && |
186 event.IsShiftDown()) { | 182 event.IsShiftDown()) { |
187 // If shift+del didn't change the text, we let this delete an entry from | 183 // If shift+del didn't change the text, we let this delete an entry from |
188 // the popup. We can't check to see if the IME handled it because even if | 184 // the popup. We can't check to see if the IME handled it because even if |
189 // nothing is selected, the IME or the TextView still report handling it. | 185 // nothing is selected, the IME or the TextView still report handling it. |
190 if (model_->popup_model()->IsOpen()) | 186 if (model_->popup_model()->IsOpen()) |
191 model_->popup_model()->TryDeletingCurrentItem(); | 187 model_->popup_model()->TryDeletingCurrentItem(); |
192 } else if (!handled && event.key_code() == ui::VKEY_UP) { | 188 } else if (!handled && event.key_code() == ui::VKEY_UP) { |
193 model_->OnUpOrDownKeyPressed(-1); | 189 model_->OnUpOrDownKeyPressed(-1); |
194 handled = true; | 190 handled = true; |
195 } else if (!handled && event.key_code() == ui::VKEY_DOWN) { | 191 } else if (!handled && event.key_code() == ui::VKEY_DOWN) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 model_->OnWillKillFocus(NULL); | 244 model_->OnWillKillFocus(NULL); |
249 // Close the popup. | 245 // Close the popup. |
250 ClosePopup(); | 246 ClosePopup(); |
251 // Tell the model to reset itself. | 247 // Tell the model to reset itself. |
252 model_->OnKillFocus(); | 248 model_->OnKillFocus(); |
253 controller_->OnKillFocus(); | 249 controller_->OnKillFocus(); |
254 } | 250 } |
255 | 251 |
256 //////////////////////////////////////////////////////////////////////////////// | 252 //////////////////////////////////////////////////////////////////////////////// |
257 // AutocompleteEditViewViews, views::View implementation: | 253 // AutocompleteEditViewViews, views::View implementation: |
258 | |
259 bool AutocompleteEditViewViews::OnMousePressed( | |
260 const views::MouseEvent& event) { | |
261 if (event.IsLeftMouseButton()) { | |
262 // Button press event may change the selection, we need to record the change | |
263 // and report it to |model_| later when button is released. | |
264 OnBeforePossibleChange(); | |
265 } | |
266 // Pass the event through to TextfieldViews. | |
267 return false; | |
268 } | |
269 | |
270 void AutocompleteEditViewViews::Layout() { | 254 void AutocompleteEditViewViews::Layout() { |
271 gfx::Insets insets = GetInsets(); | 255 gfx::Insets insets = GetInsets(); |
272 textfield_->SetBounds(insets.left(), insets.top(), | 256 textfield_->SetBounds(insets.left(), insets.top(), |
273 width() - insets.width(), | 257 width() - insets.width(), |
274 height() - insets.height()); | 258 height() - insets.height()); |
275 } | 259 } |
276 | 260 |
277 void AutocompleteEditViewViews::GetAccessibleState( | 261 void AutocompleteEditViewViews::GetAccessibleState( |
278 ui::AccessibleViewState* state) { | 262 ui::AccessibleViewState* state) { |
279 state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION); | 263 state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION); |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 | 455 |
472 void AutocompleteEditViewViews::OnRevertTemporaryText() { | 456 void AutocompleteEditViewViews::OnRevertTemporaryText() { |
473 textfield_->SelectRange(saved_temporary_selection_); | 457 textfield_->SelectRange(saved_temporary_selection_); |
474 TextChanged(); | 458 TextChanged(); |
475 } | 459 } |
476 | 460 |
477 void AutocompleteEditViewViews::OnBeforePossibleChange() { | 461 void AutocompleteEditViewViews::OnBeforePossibleChange() { |
478 // Record our state. | 462 // Record our state. |
479 text_before_change_ = GetText(); | 463 text_before_change_ = GetText(); |
480 textfield_->GetSelectedRange(&sel_before_change_); | 464 textfield_->GetSelectedRange(&sel_before_change_); |
| 465 ime_composing_before_change_ = textfield_->IsIMEComposing(); |
481 } | 466 } |
482 | 467 |
483 bool AutocompleteEditViewViews::OnAfterPossibleChange() { | 468 bool AutocompleteEditViewViews::OnAfterPossibleChange() { |
484 // OnAfterPossibleChange should be called once per modification, | |
485 // and we should ignore if this is called while a key event is being handled | |
486 // because OnAfterPossibleChagne will be called after the key event is | |
487 // actually handled. | |
488 if (handling_key_press_) { | |
489 content_maybe_changed_by_key_press_ = true; | |
490 return false; | |
491 } | |
492 ui::Range new_sel; | 469 ui::Range new_sel; |
493 textfield_->GetSelectedRange(&new_sel); | 470 textfield_->GetSelectedRange(&new_sel); |
494 | 471 |
495 size_t length = GetTextLength(); | 472 size_t length = GetTextLength(); |
496 bool at_end_of_edit = (new_sel.start() == length && new_sel.end() == length); | 473 bool at_end_of_edit = (new_sel.start() == length && new_sel.end() == length); |
497 | 474 |
498 // See if the text or selection have changed since OnBeforePossibleChange(). | 475 // See if the text or selection have changed since OnBeforePossibleChange(). |
499 string16 new_text = GetText(); | 476 string16 new_text = GetText(); |
500 text_changed_ = (new_text != text_before_change_); | 477 bool text_changed = (new_text != text_before_change_) || |
| 478 (ime_composing_before_change_ != textfield_->IsIMEComposing()); |
501 bool selection_differs = | 479 bool selection_differs = |
502 !((sel_before_change_.is_empty() && new_sel.is_empty()) || | 480 !((sel_before_change_.is_empty() && new_sel.is_empty()) || |
503 sel_before_change_.EqualsIgnoringDirection(new_sel)); | 481 sel_before_change_.EqualsIgnoringDirection(new_sel)); |
504 | 482 |
505 // When the user has deleted text, we don't allow inline autocomplete. Make | 483 // When the user has deleted text, we don't allow inline autocomplete. Make |
506 // sure to not flag cases like selecting part of the text and then pasting | 484 // sure to not flag cases like selecting part of the text and then pasting |
507 // (or typing) the prefix of that selection. (We detect these by making | 485 // (or typing) the prefix of that selection. (We detect these by making |
508 // sure the caret, which should be after any insertion, hasn't moved | 486 // sure the caret, which should be after any insertion, hasn't moved |
509 // forward of the old selection start.) | 487 // forward of the old selection start.) |
510 bool just_deleted_text = | 488 bool just_deleted_text = |
511 (text_before_change_.length() > new_text.length()) && | 489 (text_before_change_.length() > new_text.length()) && |
512 (new_sel.start() <= sel_before_change_.GetMin()); | 490 (new_sel.start() <= sel_before_change_.GetMin()); |
513 | 491 |
514 delete_at_end_pressed_ = false; | |
515 | |
516 bool something_changed = model_->OnAfterPossibleChange(new_text, | 492 bool something_changed = model_->OnAfterPossibleChange(new_text, |
517 selection_differs, text_changed_, just_deleted_text, at_end_of_edit); | 493 selection_differs, text_changed, just_deleted_text, at_end_of_edit); |
518 | 494 |
519 // If only selection was changed, we don't need to call |model_|'s | 495 // If only selection was changed, we don't need to call |model_|'s |
520 // OnChanged() method, which is called in TextChanged(). | 496 // OnChanged() method, which is called in TextChanged(). |
521 // But we still need to call EmphasizeURLComponents() to make sure the text | 497 // But we still need to call EmphasizeURLComponents() to make sure the text |
522 // attributes are updated correctly. | 498 // attributes are updated correctly. |
523 if (something_changed && text_changed_) { | 499 if (something_changed && text_changed) |
524 TextChanged(); | 500 TextChanged(); |
525 } else if (selection_differs) { | 501 else if (selection_differs) |
526 EmphasizeURLComponents(); | 502 EmphasizeURLComponents(); |
527 } else if (delete_was_pressed_ && at_end_of_edit) { | 503 else if (delete_at_end_pressed_) |
528 delete_at_end_pressed_ = true; | |
529 model_->OnChanged(); | 504 model_->OnChanged(); |
530 } | |
531 delete_was_pressed_ = false; | |
532 | 505 |
533 return something_changed; | 506 return something_changed; |
534 } | 507 } |
535 | 508 |
536 gfx::NativeView AutocompleteEditViewViews::GetNativeView() const { | 509 gfx::NativeView AutocompleteEditViewViews::GetNativeView() const { |
537 return GetWidget()->GetNativeView(); | 510 return GetWidget()->GetNativeView(); |
538 } | 511 } |
539 | 512 |
540 CommandUpdater* AutocompleteEditViewViews::GetCommandUpdater() { | 513 CommandUpdater* AutocompleteEditViewViews::GetCommandUpdater() { |
541 return command_updater_; | 514 return command_updater_; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
580 const NotificationDetails& details) { | 553 const NotificationDetails& details) { |
581 DCHECK(type == NotificationType::BROWSER_THEME_CHANGED); | 554 DCHECK(type == NotificationType::BROWSER_THEME_CHANGED); |
582 SetBaseColor(); | 555 SetBaseColor(); |
583 } | 556 } |
584 | 557 |
585 //////////////////////////////////////////////////////////////////////////////// | 558 //////////////////////////////////////////////////////////////////////////////// |
586 // AutocompleteEditViewViews, views::TextfieldController implementation: | 559 // AutocompleteEditViewViews, views::TextfieldController implementation: |
587 | 560 |
588 void AutocompleteEditViewViews::ContentsChanged(views::Textfield* sender, | 561 void AutocompleteEditViewViews::ContentsChanged(views::Textfield* sender, |
589 const string16& new_contents) { | 562 const string16& new_contents) { |
590 if (handling_key_press_) | |
591 content_maybe_changed_by_key_press_ = true; | |
592 } | 563 } |
593 | 564 |
594 bool AutocompleteEditViewViews::HandleKeyEvent( | 565 bool AutocompleteEditViewViews::HandleKeyEvent( |
595 views::Textfield* textfield, | 566 views::Textfield* textfield, |
596 const views::KeyEvent& event) { | 567 const views::KeyEvent& event) { |
597 delete_was_pressed_ = event.key_code() == ui::VKEY_DELETE; | 568 delete_at_end_pressed_ = false; |
598 | |
599 // Reset |text_changed_| before passing the key event on to the text view. | |
600 text_changed_ = false; | |
601 OnBeforePossibleChange(); | |
602 handling_key_press_ = true; | |
603 content_maybe_changed_by_key_press_ = false; | |
604 | 569 |
605 if (event.key_code() == ui::VKEY_BACK) { | 570 if (event.key_code() == ui::VKEY_BACK) { |
606 // Checks if it's currently in keyword search mode. | 571 // Checks if it's currently in keyword search mode. |
607 if (model_->is_keyword_hint() || model_->keyword().empty()) | 572 if (model_->is_keyword_hint() || model_->keyword().empty()) |
608 return false; | 573 return false; |
609 // If there is selection, let textfield handle the backspace. | 574 // If there is selection, let textfield handle the backspace. |
610 if (!textfield_->GetSelectedText().empty()) | 575 if (textfield_->HasSelection()) |
611 return false; | 576 return false; |
612 // If not at the begining of the text, let textfield handle the backspace. | 577 // If not at the begining of the text, let textfield handle the backspace. |
613 if (textfield_->GetCursorPosition()) | 578 if (textfield_->GetCursorPosition()) |
614 return false; | 579 return false; |
615 model_->ClearKeyword(GetText()); | 580 model_->ClearKeyword(GetText()); |
616 return true; | 581 return true; |
617 } | 582 } |
618 | 583 |
| 584 if (event.key_code() == ui::VKEY_DELETE && !event.IsAltDown()) { |
| 585 delete_at_end_pressed_ = |
| 586 (!textfield_->HasSelection() && |
| 587 textfield_->GetCursorPosition() == textfield_->text().length()); |
| 588 } |
| 589 |
619 return false; | 590 return false; |
620 } | 591 } |
621 | 592 |
| 593 void AutocompleteEditViewViews::OnBeforeUserAction(views::Textfield* sender) { |
| 594 OnBeforePossibleChange(); |
| 595 } |
| 596 |
| 597 void AutocompleteEditViewViews::OnAfterUserAction(views::Textfield* sender) { |
| 598 OnAfterPossibleChange(); |
| 599 } |
| 600 |
622 //////////////////////////////////////////////////////////////////////////////// | 601 //////////////////////////////////////////////////////////////////////////////// |
623 // AutocompleteEditViewViews, private: | 602 // AutocompleteEditViewViews, private: |
624 | 603 |
625 size_t AutocompleteEditViewViews::GetTextLength() const { | 604 size_t AutocompleteEditViewViews::GetTextLength() const { |
626 // TODO(oshima): Support instant, IME. | 605 // TODO(oshima): Support instant, IME. |
627 return textfield_->text().length(); | 606 return textfield_->text().length(); |
628 } | 607 } |
629 | 608 |
630 void AutocompleteEditViewViews::EmphasizeURLComponents() { | 609 void AutocompleteEditViewViews::EmphasizeURLComponents() { |
631 // TODO(oshima): Update URL visual style | 610 // TODO(oshima): Update URL visual style |
(...skipping 26 matching lines...) Expand all Loading... |
658 AutocompletePopupView* AutocompleteEditViewViews::CreatePopupView( | 637 AutocompletePopupView* AutocompleteEditViewViews::CreatePopupView( |
659 Profile* profile, | 638 Profile* profile, |
660 const View* location_bar) { | 639 const View* location_bar) { |
661 #if defined(TOUCH_UI) | 640 #if defined(TOUCH_UI) |
662 return new TouchAutocompletePopupContentsView( | 641 return new TouchAutocompletePopupContentsView( |
663 #else | 642 #else |
664 return new AutocompletePopupContentsView( | 643 return new AutocompletePopupContentsView( |
665 #endif | 644 #endif |
666 gfx::Font(), this, model_.get(), profile, location_bar); | 645 gfx::Font(), this, model_.get(), profile, location_bar); |
667 } | 646 } |
OLD | NEW |