• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/autocomplete/autocomplete_edit_view_views.h"
6 
7 #include "base/logging.h"
8 #include "base/string_util.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/autocomplete/autocomplete_edit.h"
12 #include "chrome/browser/autocomplete/autocomplete_match.h"
13 #include "chrome/browser/autocomplete/autocomplete_popup_model.h"
14 #include "chrome/browser/command_updater.h"
15 #include "chrome/browser/ui/views/autocomplete/autocomplete_popup_contents_view.h"
16 #include "chrome/browser/ui/views/autocomplete/touch_autocomplete_popup_contents_view.h"
17 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
18 #include "content/browser/tab_contents/tab_contents.h"
19 #include "content/common/notification_service.h"
20 #include "googleurl/src/gurl.h"
21 #include "grit/generated_resources.h"
22 #include "net/base/escape.h"
23 #include "ui/base/accessibility/accessible_view_state.h"
24 #include "ui/base/dragdrop/drag_drop_types.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/gfx/font.h"
28 #include "views/border.h"
29 #include "views/controls/textfield/textfield.h"
30 #include "views/layout/fill_layout.h"
31 
32 namespace {
33 
34 // Textfield for autocomplete that intercepts events that are necessary
35 // for AutocompleteEditViewViews.
36 class AutocompleteTextfield : public views::Textfield {
37  public:
AutocompleteTextfield(AutocompleteEditViewViews * autocomplete_edit_view)38   explicit AutocompleteTextfield(
39       AutocompleteEditViewViews* autocomplete_edit_view)
40       : views::Textfield(views::Textfield::STYLE_DEFAULT),
41         autocomplete_edit_view_(autocomplete_edit_view) {
42     DCHECK(autocomplete_edit_view_);
43     RemoveBorder();
44   }
45 
46   // views::View implementation
OnFocus()47   virtual void OnFocus() OVERRIDE {
48     views::Textfield::OnFocus();
49     autocomplete_edit_view_->HandleFocusIn();
50   }
51 
OnBlur()52   virtual void OnBlur() OVERRIDE {
53     views::Textfield::OnBlur();
54     autocomplete_edit_view_->HandleFocusOut();
55   }
56 
OnKeyPressed(const views::KeyEvent & event)57   virtual bool OnKeyPressed(const views::KeyEvent& event) OVERRIDE {
58     bool handled = views::Textfield::OnKeyPressed(event);
59     return autocomplete_edit_view_->HandleAfterKeyEvent(event, handled) ||
60         handled;
61   }
62 
OnKeyReleased(const views::KeyEvent & event)63   virtual bool OnKeyReleased(const views::KeyEvent& event) OVERRIDE {
64     return autocomplete_edit_view_->HandleKeyReleaseEvent(event);
65   }
66 
IsFocusable() const67   virtual bool IsFocusable() const OVERRIDE {
68     // Bypass Textfield::IsFocusable. The omnibox in popup window requires
69     // focus in order for text selection to work.
70     return views::View::IsFocusable();
71   }
72 
73  private:
74   AutocompleteEditViewViews* autocomplete_edit_view_;
75 
76   DISALLOW_COPY_AND_ASSIGN(AutocompleteTextfield);
77 };
78 
79 // Stores omnibox state for each tab.
80 struct ViewState {
ViewState__anonea1bc25b0111::ViewState81   explicit ViewState(const ui::Range& selection_range)
82       : selection_range(selection_range) {
83   }
84 
85   // Range of selected text.
86   ui::Range selection_range;
87 };
88 
89 struct AutocompleteEditState {
AutocompleteEditState__anonea1bc25b0111::AutocompleteEditState90   AutocompleteEditState(const AutocompleteEditModel::State& model_state,
91                         const ViewState& view_state)
92       : model_state(model_state),
93         view_state(view_state) {
94   }
95 
96   const AutocompleteEditModel::State model_state;
97   const ViewState view_state;
98 };
99 
100 // Returns a lazily initialized property bag accessor for saving our state in a
101 // TabContents.
GetStateAccessor()102 PropertyAccessor<AutocompleteEditState>* GetStateAccessor() {
103   static PropertyAccessor<AutocompleteEditState> state;
104   return &state;
105 }
106 
107 const int kAutocompleteVerticalMargin = 4;
108 
109 }  // namespace
110 
AutocompleteEditViewViews(AutocompleteEditController * controller,ToolbarModel * toolbar_model,Profile * profile,CommandUpdater * command_updater,bool popup_window_mode,const views::View * location_bar)111 AutocompleteEditViewViews::AutocompleteEditViewViews(
112     AutocompleteEditController* controller,
113     ToolbarModel* toolbar_model,
114     Profile* profile,
115     CommandUpdater* command_updater,
116     bool popup_window_mode,
117     const views::View* location_bar)
118     : model_(new AutocompleteEditModel(this, controller, profile)),
119       popup_view_(CreatePopupView(profile, location_bar)),
120       controller_(controller),
121       toolbar_model_(toolbar_model),
122       command_updater_(command_updater),
123       popup_window_mode_(popup_window_mode),
124       security_level_(ToolbarModel::NONE),
125       ime_composing_before_change_(false),
126       delete_at_end_pressed_(false) {
127   set_border(views::Border::CreateEmptyBorder(kAutocompleteVerticalMargin, 0,
128                                               kAutocompleteVerticalMargin, 0));
129 }
130 
~AutocompleteEditViewViews()131 AutocompleteEditViewViews::~AutocompleteEditViewViews() {
132   NotificationService::current()->Notify(
133       NotificationType::AUTOCOMPLETE_EDIT_DESTROYED,
134       Source<AutocompleteEditViewViews>(this),
135       NotificationService::NoDetails());
136   // Explicitly teardown members which have a reference to us.  Just to be safe
137   // we want them to be destroyed before destroying any other internal state.
138   popup_view_.reset();
139   model_.reset();
140 }
141 
142 ////////////////////////////////////////////////////////////////////////////////
143 // AutocompleteEditViewViews public:
144 
Init()145 void AutocompleteEditViewViews::Init() {
146   // The height of the text view is going to change based on the font used.  We
147   // don't want to stretch the height, and we want it vertically centered.
148   // TODO(oshima): make sure the above happens with views.
149   textfield_ = new AutocompleteTextfield(this);
150   textfield_->SetController(this);
151 
152 #if defined(TOUCH_UI)
153   textfield_->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
154                       ResourceBundle::LargeFont));
155 #endif
156 
157   if (popup_window_mode_)
158     textfield_->SetReadOnly(true);
159 
160   // Manually invoke SetBaseColor() because TOOLKIT_VIEWS doesn't observe
161   // themes.
162   SetBaseColor();
163 }
164 
SetBaseColor()165 void AutocompleteEditViewViews::SetBaseColor() {
166   // TODO(oshima): Implment style change.
167   NOTIMPLEMENTED();
168 }
169 
HandleAfterKeyEvent(const views::KeyEvent & event,bool handled)170 bool AutocompleteEditViewViews::HandleAfterKeyEvent(
171     const views::KeyEvent& event,
172     bool handled) {
173   if (event.key_code() == ui::VKEY_RETURN) {
174     bool alt_held = event.IsAltDown();
175     model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false);
176     handled = true;
177   } else if (!handled && event.key_code() == ui::VKEY_ESCAPE) {
178     // We can handle the Escape key if textfield did not handle it.
179     // If it's not handled by us, then we need to propagate it up to the parent
180     // widgets, so that Escape accelerator can still work.
181     handled = model_->OnEscapeKeyPressed();
182   } else if (event.key_code() == ui::VKEY_CONTROL) {
183     // Omnibox2 can switch its contents while pressing a control key. To switch
184     // the contents of omnibox2, we notify the AutocompleteEditModel class when
185     // the control-key state is changed.
186     model_->OnControlKeyChanged(true);
187   } else if (!handled && event.key_code() == ui::VKEY_DELETE &&
188              event.IsShiftDown()) {
189     // If shift+del didn't change the text, we let this delete an entry from
190     // the popup.  We can't check to see if the IME handled it because even if
191     // nothing is selected, the IME or the TextView still report handling it.
192     if (model_->popup_model()->IsOpen())
193       model_->popup_model()->TryDeletingCurrentItem();
194   } else if (!handled && event.key_code() == ui::VKEY_UP) {
195     model_->OnUpOrDownKeyPressed(-1);
196     handled = true;
197   } else if (!handled && event.key_code() == ui::VKEY_DOWN) {
198     model_->OnUpOrDownKeyPressed(1);
199     handled = true;
200   } else if (!handled &&
201              event.key_code() == ui::VKEY_TAB &&
202              !event.IsShiftDown() &&
203              !event.IsControlDown()) {
204     if (model_->is_keyword_hint()) {
205       handled = model_->AcceptKeyword();
206     } else {
207       string16::size_type start = 0;
208       string16::size_type end = 0;
209       size_t length = GetTextLength();
210       GetSelectionBounds(&start, &end);
211       if (start != end || start < length) {
212         OnBeforePossibleChange();
213         SelectRange(length, length);
214         OnAfterPossibleChange();
215         handled = true;
216       }
217 
218       // TODO(Oshima): handle instant
219     }
220   }
221   // TODO(oshima): page up & down
222 
223   return handled;
224 }
225 
HandleKeyReleaseEvent(const views::KeyEvent & event)226 bool AutocompleteEditViewViews::HandleKeyReleaseEvent(
227     const views::KeyEvent& event) {
228   // Omnibox2 can switch its contents while pressing a control key. To switch
229   // the contents of omnibox2, we notify the AutocompleteEditModel class when
230   // the control-key state is changed.
231   if (event.key_code() == ui::VKEY_CONTROL) {
232     // TODO(oshima): investigate if we need to support keyboard with two
233     // controls. See autocomplete_edit_view_gtk.cc.
234     model_->OnControlKeyChanged(false);
235     return true;
236   }
237   return false;
238 }
239 
HandleFocusIn()240 void AutocompleteEditViewViews::HandleFocusIn() {
241   // TODO(oshima): Get control key state.
242   model_->OnSetFocus(false);
243   // Don't call controller_->OnSetFocus as this view has already
244   // acquired the focus.
245 }
246 
HandleFocusOut()247 void AutocompleteEditViewViews::HandleFocusOut() {
248   // TODO(oshima): we don't have native view. This requires
249   // further refactoring.
250   model_->OnWillKillFocus(NULL);
251   // Close the popup.
252   ClosePopup();
253   // Tell the model to reset itself.
254   model_->OnKillFocus();
255   controller_->OnKillFocus();
256 }
257 
258 ////////////////////////////////////////////////////////////////////////////////
259 // AutocompleteEditViewViews, views::View implementation:
Layout()260 void AutocompleteEditViewViews::Layout() {
261   gfx::Insets insets = GetInsets();
262   textfield_->SetBounds(insets.left(), insets.top(),
263                         width() - insets.width(),
264                         height() - insets.height());
265 }
266 
GetAccessibleState(ui::AccessibleViewState * state)267 void AutocompleteEditViewViews::GetAccessibleState(
268     ui::AccessibleViewState* state) {
269   state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION);
270 }
271 
272 ////////////////////////////////////////////////////////////////////////////////
273 // AutocompleteEditViewViews, AutocopmleteEditView implementation:
274 
model()275 AutocompleteEditModel* AutocompleteEditViewViews::model() {
276   return model_.get();
277 }
278 
model() const279 const AutocompleteEditModel* AutocompleteEditViewViews::model() const {
280   return model_.get();
281 }
282 
SaveStateToTab(TabContents * tab)283 void AutocompleteEditViewViews::SaveStateToTab(TabContents* tab) {
284   DCHECK(tab);
285 
286   // NOTE: GetStateForTabSwitch may affect GetSelection, so order is important.
287   AutocompleteEditModel::State model_state = model_->GetStateForTabSwitch();
288   ui::Range selection;
289   textfield_->GetSelectedRange(&selection);
290   GetStateAccessor()->SetProperty(
291       tab->property_bag(),
292       AutocompleteEditState(model_state, ViewState(selection)));
293 }
294 
Update(const TabContents * contents)295 void AutocompleteEditViewViews::Update(const TabContents* contents) {
296   // NOTE: We're getting the URL text here from the ToolbarModel.
297   bool visibly_changed_permanent_text =
298       model_->UpdatePermanentText(WideToUTF16Hack(toolbar_model_->GetText()));
299 
300   ToolbarModel::SecurityLevel security_level =
301         toolbar_model_->GetSecurityLevel();
302   bool changed_security_level = (security_level != security_level_);
303   security_level_ = security_level;
304 
305   // TODO(oshima): Copied from gtk implementation which is
306   // slightly different from WIN impl. Find out the correct implementation
307   // for views-implementation.
308   if (contents) {
309     RevertAll();
310     const AutocompleteEditState* state =
311         GetStateAccessor()->GetProperty(contents->property_bag());
312     if (state) {
313       model_->RestoreState(state->model_state);
314 
315       // Move the marks for the cursor and the other end of the selection to
316       // the previously-saved offsets (but preserve PRIMARY).
317       textfield_->SelectRange(state->view_state.selection_range);
318     }
319   } else if (visibly_changed_permanent_text) {
320     RevertAll();
321   } else if (changed_security_level) {
322     EmphasizeURLComponents();
323   }
324 }
325 
OpenURL(const GURL & url,WindowOpenDisposition disposition,PageTransition::Type transition,const GURL & alternate_nav_url,size_t selected_line,const string16 & keyword)326 void AutocompleteEditViewViews::OpenURL(const GURL& url,
327                                         WindowOpenDisposition disposition,
328                                         PageTransition::Type transition,
329                                         const GURL& alternate_nav_url,
330                                         size_t selected_line,
331                                         const string16& keyword) {
332   if (!url.is_valid())
333     return;
334 
335   model_->OpenURL(url, disposition, transition, alternate_nav_url,
336                   selected_line, keyword);
337 }
338 
GetText() const339 string16 AutocompleteEditViewViews::GetText() const {
340   // TODO(oshima): IME support
341   return textfield_->text();
342 }
343 
IsEditingOrEmpty() const344 bool AutocompleteEditViewViews::IsEditingOrEmpty() const {
345   return model_->user_input_in_progress() || (GetTextLength() == 0);
346 }
347 
GetIcon() const348 int AutocompleteEditViewViews::GetIcon() const {
349   return IsEditingOrEmpty() ?
350       AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) :
351       toolbar_model_->GetIcon();
352 }
353 
SetUserText(const string16 & text)354 void AutocompleteEditViewViews::SetUserText(const string16& text) {
355   SetUserText(text, text, true);
356 }
357 
SetUserText(const string16 & text,const string16 & display_text,bool update_popup)358 void AutocompleteEditViewViews::SetUserText(const string16& text,
359                                             const string16& display_text,
360                                             bool update_popup) {
361   model_->SetUserText(text);
362   SetWindowTextAndCaretPos(display_text, display_text.length());
363   if (update_popup)
364     UpdatePopup();
365   TextChanged();
366 }
367 
SetWindowTextAndCaretPos(const string16 & text,size_t caret_pos)368 void AutocompleteEditViewViews::SetWindowTextAndCaretPos(
369     const string16& text,
370     size_t caret_pos) {
371   const ui::Range range(caret_pos, caret_pos);
372   SetTextAndSelectedRange(text, range);
373 }
374 
SetForcedQuery()375 void AutocompleteEditViewViews::SetForcedQuery() {
376   const string16 current_text(GetText());
377   const size_t start = current_text.find_first_not_of(kWhitespaceUTF16);
378   if (start == string16::npos || (current_text[start] != '?')) {
379     SetUserText(ASCIIToUTF16("?"));
380   } else {
381     SelectRange(current_text.size(), start + 1);
382   }
383 }
384 
IsSelectAll()385 bool AutocompleteEditViewViews::IsSelectAll() {
386   // TODO(oshima): IME support.
387   return textfield_->text() == textfield_->GetSelectedText();
388 }
389 
DeleteAtEndPressed()390 bool AutocompleteEditViewViews::DeleteAtEndPressed() {
391   return delete_at_end_pressed_;
392 }
393 
GetSelectionBounds(string16::size_type * start,string16::size_type * end)394 void AutocompleteEditViewViews::GetSelectionBounds(
395     string16::size_type* start,
396     string16::size_type* end) {
397   ui::Range range;
398   textfield_->GetSelectedRange(&range);
399   *start = static_cast<size_t>(range.end());
400   *end = static_cast<size_t>(range.start());
401 }
402 
SelectAll(bool reversed)403 void AutocompleteEditViewViews::SelectAll(bool reversed) {
404   if (reversed)
405     SelectRange(GetTextLength(), 0);
406   else
407     SelectRange(0, GetTextLength());
408 }
409 
RevertAll()410 void AutocompleteEditViewViews::RevertAll() {
411   ClosePopup();
412   model_->Revert();
413   TextChanged();
414 }
415 
UpdatePopup()416 void AutocompleteEditViewViews::UpdatePopup() {
417   model_->SetInputInProgress(true);
418   if (!model_->has_focus())
419     return;
420 
421   // Don't inline autocomplete when the caret/selection isn't at the end of
422   // the text, or in the middle of composition.
423   ui::Range sel;
424   textfield_->GetSelectedRange(&sel);
425   bool no_inline_autocomplete =
426       sel.GetMax() < GetTextLength() || textfield_->IsIMEComposing();
427 
428   model_->StartAutocomplete(!sel.is_empty(), no_inline_autocomplete);
429 }
430 
ClosePopup()431 void AutocompleteEditViewViews::ClosePopup() {
432   model_->StopAutocomplete();
433 }
434 
SetFocus()435 void AutocompleteEditViewViews::SetFocus() {
436   // In views-implementation, the focus is on textfield rather than
437   // AutocompleteEditView.
438   textfield_->RequestFocus();
439 }
440 
OnTemporaryTextMaybeChanged(const string16 & display_text,bool save_original_selection)441 void AutocompleteEditViewViews::OnTemporaryTextMaybeChanged(
442     const string16& display_text,
443     bool save_original_selection) {
444   if (save_original_selection)
445     textfield_->GetSelectedRange(&saved_temporary_selection_);
446 
447   SetWindowTextAndCaretPos(display_text, display_text.length());
448   TextChanged();
449 }
450 
OnInlineAutocompleteTextMaybeChanged(const string16 & display_text,size_t user_text_length)451 bool AutocompleteEditViewViews::OnInlineAutocompleteTextMaybeChanged(
452     const string16& display_text,
453     size_t user_text_length) {
454   if (display_text == GetText())
455     return false;
456   ui::Range range(display_text.size(), user_text_length);
457   SetTextAndSelectedRange(display_text, range);
458   TextChanged();
459   return true;
460 }
461 
OnRevertTemporaryText()462 void AutocompleteEditViewViews::OnRevertTemporaryText() {
463   textfield_->SelectRange(saved_temporary_selection_);
464   TextChanged();
465 }
466 
OnBeforePossibleChange()467 void AutocompleteEditViewViews::OnBeforePossibleChange() {
468   // Record our state.
469   text_before_change_ = GetText();
470   textfield_->GetSelectedRange(&sel_before_change_);
471   ime_composing_before_change_ = textfield_->IsIMEComposing();
472 }
473 
OnAfterPossibleChange()474 bool AutocompleteEditViewViews::OnAfterPossibleChange() {
475   ui::Range new_sel;
476   textfield_->GetSelectedRange(&new_sel);
477 
478   // See if the text or selection have changed since OnBeforePossibleChange().
479   const string16 new_text = GetText();
480   const bool text_changed = (new_text != text_before_change_) ||
481       (ime_composing_before_change_ != textfield_->IsIMEComposing());
482   const bool selection_differs =
483       !((sel_before_change_.is_empty() && new_sel.is_empty()) ||
484         sel_before_change_.EqualsIgnoringDirection(new_sel));
485 
486   // When the user has deleted text, we don't allow inline autocomplete.  Make
487   // sure to not flag cases like selecting part of the text and then pasting
488   // (or typing) the prefix of that selection.  (We detect these by making
489   // sure the caret, which should be after any insertion, hasn't moved
490   // forward of the old selection start.)
491   const bool just_deleted_text =
492       (text_before_change_.length() > new_text.length()) &&
493       (new_sel.start() <= sel_before_change_.GetMin());
494 
495   const bool something_changed = model_->OnAfterPossibleChange(
496       new_text, new_sel.start(), new_sel.end(), selection_differs,
497       text_changed, just_deleted_text, !textfield_->IsIMEComposing());
498 
499   // If only selection was changed, we don't need to call |model_|'s
500   // OnChanged() method, which is called in TextChanged().
501   // But we still need to call EmphasizeURLComponents() to make sure the text
502   // attributes are updated correctly.
503   if (something_changed && text_changed)
504     TextChanged();
505   else if (selection_differs)
506     EmphasizeURLComponents();
507   else if (delete_at_end_pressed_)
508     model_->OnChanged();
509 
510   return something_changed;
511 }
512 
GetNativeView() const513 gfx::NativeView AutocompleteEditViewViews::GetNativeView() const {
514   return GetWidget()->GetNativeView();
515 }
516 
GetCommandUpdater()517 CommandUpdater* AutocompleteEditViewViews::GetCommandUpdater() {
518   return command_updater_;
519 }
520 
SetInstantSuggestion(const string16 & input,bool animate_to_complete)521 void AutocompleteEditViewViews::SetInstantSuggestion(const string16& input,
522                                                      bool animate_to_complete) {
523   NOTIMPLEMENTED();
524 }
525 
GetInstantSuggestion() const526 string16 AutocompleteEditViewViews::GetInstantSuggestion() const {
527   NOTIMPLEMENTED();
528   return string16();
529 }
530 
TextWidth() const531 int AutocompleteEditViewViews::TextWidth() const {
532   // TODO(oshima): add horizontal margin.
533   return textfield_->font().GetStringWidth(textfield_->text());
534 }
535 
IsImeComposing() const536 bool AutocompleteEditViewViews::IsImeComposing() const {
537   return false;
538 }
539 
AddToView(views::View * parent)540 views::View* AutocompleteEditViewViews::AddToView(views::View* parent) {
541   parent->AddChildView(this);
542   AddChildView(textfield_);
543   return this;
544 }
545 
OnPerformDrop(const views::DropTargetEvent & event)546 int AutocompleteEditViewViews::OnPerformDrop(
547     const views::DropTargetEvent& event) {
548   NOTIMPLEMENTED();
549   return ui::DragDropTypes::DRAG_NONE;
550 }
551 
552 ////////////////////////////////////////////////////////////////////////////////
553 // AutocompleteEditViewViews, NotificationObserver implementation:
554 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)555 void AutocompleteEditViewViews::Observe(NotificationType type,
556                                       const NotificationSource& source,
557                                       const NotificationDetails& details) {
558   DCHECK(type == NotificationType::BROWSER_THEME_CHANGED);
559   SetBaseColor();
560 }
561 
562 ////////////////////////////////////////////////////////////////////////////////
563 // AutocompleteEditViewViews, views::TextfieldController implementation:
564 
ContentsChanged(views::Textfield * sender,const string16 & new_contents)565 void AutocompleteEditViewViews::ContentsChanged(views::Textfield* sender,
566                                                 const string16& new_contents) {
567 }
568 
HandleKeyEvent(views::Textfield * textfield,const views::KeyEvent & event)569 bool AutocompleteEditViewViews::HandleKeyEvent(
570     views::Textfield* textfield,
571     const views::KeyEvent& event) {
572   delete_at_end_pressed_ = false;
573 
574   if (event.key_code() == ui::VKEY_BACK) {
575     // Checks if it's currently in keyword search mode.
576     if (model_->is_keyword_hint() || model_->keyword().empty())
577       return false;
578     // If there is selection, let textfield handle the backspace.
579     if (textfield_->HasSelection())
580       return false;
581     // If not at the begining of the text, let textfield handle the backspace.
582     if (textfield_->GetCursorPosition())
583       return false;
584     model_->ClearKeyword(GetText());
585     return true;
586   }
587 
588   if (event.key_code() == ui::VKEY_DELETE && !event.IsAltDown()) {
589     delete_at_end_pressed_ =
590         (!textfield_->HasSelection() &&
591          textfield_->GetCursorPosition() == textfield_->text().length());
592   }
593 
594   return false;
595 }
596 
OnBeforeUserAction(views::Textfield * sender)597 void AutocompleteEditViewViews::OnBeforeUserAction(views::Textfield* sender) {
598   OnBeforePossibleChange();
599 }
600 
OnAfterUserAction(views::Textfield * sender)601 void AutocompleteEditViewViews::OnAfterUserAction(views::Textfield* sender) {
602   OnAfterPossibleChange();
603 }
604 
605 ////////////////////////////////////////////////////////////////////////////////
606 // AutocompleteEditViewViews, private:
607 
GetTextLength() const608 size_t AutocompleteEditViewViews::GetTextLength() const {
609   // TODO(oshima): Support instant, IME.
610   return textfield_->text().length();
611 }
612 
EmphasizeURLComponents()613 void AutocompleteEditViewViews::EmphasizeURLComponents() {
614   // TODO(oshima): Update URL visual style
615   NOTIMPLEMENTED();
616 }
617 
TextChanged()618 void AutocompleteEditViewViews::TextChanged() {
619   EmphasizeURLComponents();
620   model_->OnChanged();
621 }
622 
SetTextAndSelectedRange(const string16 & text,const ui::Range & range)623 void AutocompleteEditViewViews::SetTextAndSelectedRange(
624     const string16& text,
625     const ui::Range& range) {
626   if (text != GetText())
627     textfield_->SetText(text);
628   textfield_->SelectRange(range);
629 }
630 
GetSelectedText() const631 string16 AutocompleteEditViewViews::GetSelectedText() const {
632   // TODO(oshima): Support instant, IME.
633   return textfield_->GetSelectedText();
634 }
635 
SelectRange(size_t caret,size_t end)636 void AutocompleteEditViewViews::SelectRange(size_t caret, size_t end) {
637   const ui::Range range(caret, end);
638   textfield_->SelectRange(range);
639 }
640 
CreatePopupView(Profile * profile,const View * location_bar)641 AutocompletePopupView* AutocompleteEditViewViews::CreatePopupView(
642     Profile* profile,
643     const View* location_bar) {
644 #if defined(TOUCH_UI)
645   return new TouchAutocompletePopupContentsView(
646 #else
647   return new AutocompletePopupContentsView(
648 #endif
649       gfx::Font(), this, model_.get(), profile, location_bar);
650 }
651