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