Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(295)

Side by Side Diff: chrome/browser/autocomplete/autocomplete_edit_view_mac.mm

Issue 113746: Overhaul omnibox focus detection on Mac. (Closed)
Patch Set: Address Pink's suggestion, add some color commentary. Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/autocomplete/autocomplete_edit_view_mac.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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_mac.h" 5 #include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
6 6
7 #include "base/sys_string_conversions.h" 7 #include "base/sys_string_conversions.h"
8 #include "chrome/browser/autocomplete/autocomplete_edit.h" 8 #include "chrome/browser/autocomplete/autocomplete_edit.h"
9 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" 9 #include "chrome/browser/autocomplete/autocomplete_popup_model.h"
10 #include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h" 10 #include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h"
11 #include "chrome/browser/tab_contents/tab_contents.h" 11 #include "chrome/browser/tab_contents/tab_contents.h"
12 12
13 // Focus-handling between |field_| and |model_| is a bit subtle.
14 // Other platforms detect change of focus, which is inconvenient
15 // without subclassing NSTextField (even with a subclass, the use of a
16 // field editor may complicate things).
17 //
18 // |model_| doesn't actually do anything when it gains focus, it just
19 // initializes. Visible activity happens only after the user edits.
20 // NSTextField delegate receives messages around starting and ending
21 // edits, so that sufcices to catch focus changes. Since all calls
22 // into |model_| start from AutocompleteEditViewMac, in the worst case
23 // we can add code to sync up the sense of focus as needed.
24 //
25 // I've added DCHECK(IsFirstResponder()) in the places which I believe
26 // should only be reachable when |field_| is being edited. If these
27 // fire, it probably means someone unexpected is calling into
28 // |model_|.
29 //
30 // Other platforms don't appear to have the sense of "key window" that
31 // Mac does (I believe their fields lose focus when the window loses
32 // focus). Rather than modifying focus outside the control's edit
33 // scope, when the window resigns key the autocomplete popup is
34 // closed. |model_| still believes it has focus, and the popup will
35 // be regenerated on the user's next edit. That seems to match how
36 // things work on other platforms.
37
13 namespace { 38 namespace {
14 39
15 // TODO(shess): This is ugly, find a better way. Using it right now 40 // TODO(shess): This is ugly, find a better way. Using it right now
16 // so that I can crib from gtk and still be able to see that I'm using 41 // so that I can crib from gtk and still be able to see that I'm using
17 // the same values easily. 42 // the same values easily.
18 const NSColor* ColorWithRGBBytes(int rr, int gg, int bb) { 43 const NSColor* ColorWithRGBBytes(int rr, int gg, int bb) {
19 DCHECK_LE(rr, 255); 44 DCHECK_LE(rr, 255);
20 DCHECK_LE(bb, 255); 45 DCHECK_LE(bb, 255);
21 DCHECK_LE(gg, 255); 46 DCHECK_LE(gg, 255);
22 return [NSColor colorWithCalibratedRed:static_cast<float>(rr)/255.0 47 return [NSColor colorWithCalibratedRed:static_cast<float>(rr)/255.0
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 // Thin Obj-C bridge class that is the delegate of the omnibox field. 116 // Thin Obj-C bridge class that is the delegate of the omnibox field.
92 // It intercepts various control delegate methods and vectors them to 117 // It intercepts various control delegate methods and vectors them to
93 // the edit view. 118 // the edit view.
94 119
95 @interface AutocompleteFieldDelegate : NSObject { 120 @interface AutocompleteFieldDelegate : NSObject {
96 @private 121 @private
97 AutocompleteEditViewMac* edit_view_; // weak, owns us. 122 AutocompleteEditViewMac* edit_view_; // weak, owns us.
98 } 123 }
99 - initWithEditView:(AutocompleteEditViewMac*)view; 124 - initWithEditView:(AutocompleteEditViewMac*)view;
100 - (void)windowDidResignKey:(NSNotification*)notification; 125 - (void)windowDidResignKey:(NSNotification*)notification;
101 - (void)windowDidBecomeKey:(NSNotification*)notification;
102 @end 126 @end
103 127
104 AutocompleteEditViewMac::AutocompleteEditViewMac( 128 AutocompleteEditViewMac::AutocompleteEditViewMac(
105 AutocompleteEditController* controller, 129 AutocompleteEditController* controller,
106 ToolbarModel* toolbar_model, 130 ToolbarModel* toolbar_model,
107 Profile* profile, 131 Profile* profile,
108 CommandUpdater* command_updater, 132 CommandUpdater* command_updater,
109 NSTextField* field) 133 NSTextField* field)
110 : model_(new AutocompleteEditModel(this, controller, profile)), 134 : model_(new AutocompleteEditModel(this, controller, profile)),
111 popup_view_(new AutocompletePopupViewMac(this, model_.get(), profile, 135 popup_view_(new AutocompletePopupViewMac(this, model_.get(), profile,
(...skipping 13 matching lines...) Expand all
125 // Needed so that editing doesn't lose the styling. 149 // Needed so that editing doesn't lose the styling.
126 [field_ setAllowsEditingTextAttributes:YES]; 150 [field_ setAllowsEditingTextAttributes:YES];
127 151
128 // Track the window's key status for signalling focus changes to 152 // Track the window's key status for signalling focus changes to
129 // |model_|. 153 // |model_|.
130 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 154 NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
131 [nc addObserver:edit_helper_ 155 [nc addObserver:edit_helper_
132 selector:@selector(windowDidResignKey:) 156 selector:@selector(windowDidResignKey:)
133 name:NSWindowDidResignKeyNotification 157 name:NSWindowDidResignKeyNotification
134 object:[field_ window]]; 158 object:[field_ window]];
135 [nc addObserver:edit_helper_
136 selector:@selector(windowDidBecomeKey:)
137 name:NSWindowDidBecomeKeyNotification
138 object:[field_ window]];
139 } 159 }
140 160
141 AutocompleteEditViewMac::~AutocompleteEditViewMac() { 161 AutocompleteEditViewMac::~AutocompleteEditViewMac() {
142 // TODO(shess): Having to be aware of destructor ordering in this 162 // TODO(shess): Having to be aware of destructor ordering in this
143 // way seems brittle. There must be a better way. 163 // way seems brittle. There must be a better way.
144 164
145 // Destroy popup view before this object in case it tries to call us 165 // Destroy popup view before this object in case it tries to call us
146 // back in the destructor. Likewise for destroying the model before 166 // back in the destructor. Likewise for destroying the model before
147 // this object. 167 // this object.
148 popup_view_.reset(); 168 popup_view_.reset();
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 SetSelectedRange(NSMakeRange(user_text_length, display_text.size())); 412 SetSelectedRange(NSMakeRange(user_text_length, display_text.size()));
393 return true; 413 return true;
394 } 414 }
395 415
396 void AutocompleteEditViewMac::OnRevertTemporaryText() { 416 void AutocompleteEditViewMac::OnRevertTemporaryText() {
397 UpdateAndStyleText(saved_temporary_text_); 417 UpdateAndStyleText(saved_temporary_text_);
398 saved_temporary_text_.clear(); 418 saved_temporary_text_.clear();
399 SetSelectedRange(saved_temporary_selection_); 419 SetSelectedRange(saved_temporary_selection_);
400 } 420 }
401 421
422 bool AutocompleteEditViewMac::IsFirstResponder() const {
423 return [field_ currentEditor] != nil ? true : false;
424 }
425
402 void AutocompleteEditViewMac::OnBeforePossibleChange() { 426 void AutocompleteEditViewMac::OnBeforePossibleChange() {
427 // We should only arrive here when the field is focussed.
428 DCHECK(IsFirstResponder());
429
403 selection_before_change_ = GetSelectedRange(); 430 selection_before_change_ = GetSelectedRange();
404 text_before_change_ = GetText(); 431 text_before_change_ = GetText();
405 } 432 }
406 433
407 bool AutocompleteEditViewMac::OnAfterPossibleChange() { 434 bool AutocompleteEditViewMac::OnAfterPossibleChange() {
435 // We should only arrive here when the field is focussed.
436 DCHECK(IsFirstResponder());
437
408 const NSRange new_selection(GetSelectedRange()); 438 const NSRange new_selection(GetSelectedRange());
409 const std::wstring new_text(GetText()); 439 const std::wstring new_text(GetText());
410 const size_t length = new_text.length(); 440 const size_t length = new_text.length();
411 441
412 const bool selection_differs = !NSEqualRanges(new_selection, 442 const bool selection_differs = !NSEqualRanges(new_selection,
413 selection_before_change_); 443 selection_before_change_);
414 const bool at_end_of_edit = (length == new_selection.location); 444 const bool at_end_of_edit = (length == new_selection.location);
415 const bool text_differs = (new_text != text_before_change_); 445 const bool text_differs = (new_text != text_before_change_);
416 446
417 // When the user has deleted text, we don't allow inline 447 // When the user has deleted text, we don't allow inline
(...skipping 25 matching lines...) Expand all
443 // is then re-created with the new autocomplete results. 473 // is then re-created with the new autocomplete results.
444 if (something_changed) { 474 if (something_changed) {
445 UpdateAndStyleText(new_text); 475 UpdateAndStyleText(new_text);
446 SetSelectedRange(new_selection); 476 SetSelectedRange(new_selection);
447 } 477 }
448 478
449 return something_changed; 479 return something_changed;
450 } 480 }
451 481
452 void AutocompleteEditViewMac::OnUpOrDownKeyPressed(bool up, bool by_page) { 482 void AutocompleteEditViewMac::OnUpOrDownKeyPressed(bool up, bool by_page) {
483 // We should only arrive here when the field is focussed.
484 DCHECK(IsFirstResponder());
485
453 const int count = by_page ? model_->result().size() : 1; 486 const int count = by_page ? model_->result().size() : 1;
454 model_->OnUpOrDownKeyPressed(up ? -count : count); 487 model_->OnUpOrDownKeyPressed(up ? -count : count);
455 } 488 }
489
456 void AutocompleteEditViewMac::OnEscapeKeyPressed() { 490 void AutocompleteEditViewMac::OnEscapeKeyPressed() {
491 // We should only arrive here when the field is focussed.
492 DCHECK(IsFirstResponder());
493
457 model_->OnEscapeKeyPressed(); 494 model_->OnEscapeKeyPressed();
458 } 495 }
459 void AutocompleteEditViewMac::OnSetFocus(bool f) { 496
460 // Only forward if we actually do have the focus. 497 void AutocompleteEditViewMac::OnWillBeginEditing() {
461 if ([field_ currentEditor]) { 498 // We should only arrive here when the field is focussed.
462 model_->OnSetFocus(f); 499 DCHECK([field_ currentEditor]);
463 } 500
501 // TODO(shess): Having the control key depressed changes the desired
502 // TLD for autocomplete, which changes the results. Not sure if we
503 // can detect that without subclassing NSTextField.
504 const bool controlDown = false;
505 model_->OnSetFocus(controlDown);
506
507 // Capture the current state.
508 OnBeforePossibleChange();
464 } 509 }
465 void AutocompleteEditViewMac::OnKillFocus() { 510
466 // TODO(shess): This would seem to be a job for |model_|. 511 void AutocompleteEditViewMac::OnDidEndEditing() {
467 ClosePopup(); 512 ClosePopup();
468 513
469 // Tell the model to reset itself. 514 // Tell the model to reset itself.
470 model_->OnKillFocus(); 515 model_->OnKillFocus();
471 } 516 }
517
518 void AutocompleteEditViewMac::OnDidResignKey() {
519 ClosePopup();
520 }
521
472 void AutocompleteEditViewMac::AcceptInput( 522 void AutocompleteEditViewMac::AcceptInput(
473 WindowOpenDisposition disposition, bool for_drop) { 523 WindowOpenDisposition disposition, bool for_drop) {
524 // We should only arrive here when the field is focussed.
525 DCHECK([field_ currentEditor]);
526
474 model_->AcceptInput(disposition, for_drop); 527 model_->AcceptInput(disposition, for_drop);
475 } 528 }
476 529
477 void AutocompleteEditViewMac::FocusLocation() { 530 void AutocompleteEditViewMac::FocusLocation() {
478 // -makeFirstResponder: will select the entire field_. If we're 531 // -makeFirstResponder: will select the entire field_. If we're
479 // already firstResponder, it's likely that we want to retain the 532 // already firstResponder, it's likely that we want to retain the
480 // current selection. 533 // current selection.
481 if (![field_ currentEditor]) { 534 if (![field_ currentEditor]) {
482 [[field_ window] makeFirstResponder:field_]; 535 [[field_ window] makeFirstResponder:field_];
483 DCHECK_EQ([field_ currentEditor], [[field_ window] firstResponder]); 536 DCHECK_EQ([field_ currentEditor], [[field_ window] firstResponder]);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 } 580 }
528 581
529 // Capture the state before the operation changes the content. 582 // Capture the state before the operation changes the content.
530 // TODO(shess): Determine if this is always redundent WRT the call 583 // TODO(shess): Determine if this is always redundent WRT the call
531 // in -controlTextDidChange:. 584 // in -controlTextDidChange:.
532 edit_view_->OnBeforePossibleChange(); 585 edit_view_->OnBeforePossibleChange();
533 return NO; 586 return NO;
534 } 587 }
535 588
536 - (void)controlTextDidBeginEditing:(NSNotification*)aNotification { 589 - (void)controlTextDidBeginEditing:(NSNotification*)aNotification {
537 edit_view_->OnSetFocus(false); 590 edit_view_->OnWillBeginEditing();
538
539 // Capture the current state.
540 edit_view_->OnBeforePossibleChange();
541 } 591 }
542 592
543 - (void)controlTextDidChange:(NSNotification*)aNotification { 593 - (void)controlTextDidChange:(NSNotification*)aNotification {
544 // Figure out what changed and notify the model_. 594 // Figure out what changed and notify the model_.
545 edit_view_->OnAfterPossibleChange(); 595 edit_view_->OnAfterPossibleChange();
546 596
547 // Then capture the new state. 597 // Then capture the new state.
548 edit_view_->OnBeforePossibleChange(); 598 edit_view_->OnBeforePossibleChange();
549 } 599 }
550 600
551 - (BOOL)control:(NSControl*)control textShouldEndEditing:(NSText*)fieldEditor { 601 - (BOOL)control:(NSControl*)control textShouldEndEditing:(NSText*)fieldEditor {
552 edit_view_->OnKillFocus(); 602 edit_view_->OnDidEndEditing();
553 603
554 return YES; 604 return YES;
555 605
556 // TODO(shess): Figure out where the selection belongs. On GTK, 606 // TODO(shess): Figure out where the selection belongs. On GTK,
557 // it's set to the start of the text. 607 // it's set to the start of the text.
558 } 608 }
559 609
560 // Signal that we've lost focus when the window resigns key. 610 // Signal that we've lost focus when the window resigns key.
561 - (void)windowDidResignKey:(NSNotification*)notification { 611 - (void)windowDidResignKey:(NSNotification*)notification {
562 edit_view_->OnKillFocus(); 612 edit_view_->OnDidResignKey();
563 }
564
565 // Signal that we may have regained focus.
566 - (void)windowDidBecomeKey:(NSNotification*)notification {
567 edit_view_->OnSetFocus(false);
568 } 613 }
569 614
570 @end 615 @end
OLDNEW
« no previous file with comments | « chrome/browser/autocomplete/autocomplete_edit_view_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698