summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_mac.h5
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_mac.mm103
-rw-r--r--chrome/browser/cocoa/autocomplete_text_field.mm22
-rw-r--r--chrome/browser/cocoa/autocomplete_text_field_editor.h15
-rw-r--r--chrome/browser/cocoa/autocomplete_text_field_editor.mm45
5 files changed, 136 insertions, 54 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
index 740fde7..d904952 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
@@ -137,6 +137,11 @@ class AutocompleteEditViewMac : public AutocompleteEditView,
// though here we cannot really do the in-place operation they do.
void EmphasizeURLComponents();
+ // Calculates text attributes according to |display_text| and applies them
+ // to the given |as| object.
+ void ApplyTextAttributes(const std::wstring& display_text,
+ NSMutableAttributedString* as);
+
scoped_ptr<AutocompleteEditModel> model_;
scoped_ptr<AutocompletePopupViewMac> popup_view_;
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
index a4a54ce..0c97205 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
@@ -406,13 +406,23 @@ void AutocompleteEditViewMac::UpdatePopup() {
if (!model_->has_focus())
return;
- // TODO(shess):
- // Shouldn't inline autocomplete when the caret/selection isn't at
- // the end of the text.
- //
- // One option would seem to be to check for a non-nil field
- // editor, and check it's selected range against its length.
- model_->StartAutocomplete(false);
+ // Comment copied from AutocompleteEditViewWin::UpdatePopup():
+ // Don't inline autocomplete when:
+ // * The user is deleting text
+ // * The caret/selection isn't at the end of the text
+ // * The user has just pasted in something that replaced all the text
+ // * The user is trying to compose something in an IME
+ bool prevent_inline_autocomplete = false;
+ NSTextView* editor = (NSTextView*)[field_ currentEditor];
+ if (editor) {
+ if ([editor hasMarkedText])
+ prevent_inline_autocomplete = true;
+
+ if (NSMaxRange([editor selectedRange]) < [[editor textStorage] length])
+ prevent_inline_autocomplete = true;
+ }
+
+ model_->StartAutocomplete(prevent_inline_autocomplete);
}
void AutocompleteEditViewMac::ClosePopup() {
@@ -426,6 +436,50 @@ void AutocompleteEditViewMac::SetText(const std::wstring& display_text) {
NSString* ss = base::SysWideToNSString(display_text);
NSMutableAttributedString* as =
[[[NSMutableAttributedString alloc] initWithString:ss] autorelease];
+
+ ApplyTextAttributes(display_text, as);
+
+ [field_ setAttributedStringValue:as];
+
+ // TODO(shess): This may be an appropriate place to call:
+ // controller_->OnChanged();
+ // In the current implementation, this tells LocationBarViewMac to
+ // mess around with |model_| and update |field_|. Unfortunately,
+ // when I look at our peer implementations, it's not entirely clear
+ // to me if this is safe. SetText() is sort of an utility method,
+ // and different callers sometimes have different needs. Research
+ // this issue so that it can be added safely.
+
+ // TODO(shess): Also, consider whether this code couldn't just
+ // manage things directly. Windows uses a series of overlaid view
+ // objects to accomplish the hinting stuff that OnChanged() does, so
+ // it makes sense to have it in the controller that lays those
+ // things out. Mac instead pushes the support into a custom
+ // text-field implementation.
+}
+
+void AutocompleteEditViewMac::SetTextAndSelectedRange(
+ const std::wstring& display_text, const NSRange range) {
+ SetText(display_text);
+ SetSelectedRange(range);
+}
+
+void AutocompleteEditViewMac::EmphasizeURLComponents() {
+ NSTextView* editor = (NSTextView*)[field_ currentEditor];
+ // If the autocomplete text field is in editing mode, then we can just change
+ // its attributes through its editor. Otherwise, we simply reset its content.
+ if (editor) {
+ NSTextStorage* storage = [editor textStorage];
+ [storage beginEditing];
+ ApplyTextAttributes(GetText(), storage);
+ [storage endEditing];
+ } else {
+ SetText(GetText());
+ }
+}
+
+void AutocompleteEditViewMac::ApplyTextAttributes(
+ const std::wstring& display_text, NSMutableAttributedString* as) {
NSFont* font = ResourceBundle::GetSharedInstance().GetFont(
ResourceBundle::BaseFont).nativeFont();
[as addAttribute:NSFontAttributeName value:font
@@ -475,38 +529,6 @@ void AutocompleteEditViewMac::SetText(const std::wstring& display_text) {
[as addAttribute:NSForegroundColorAttributeName value:color
range:ComponentToNSRange(scheme)];
}
-
- [field_ setAttributedStringValue:as];
-
- // TODO(shess): This may be an appropriate place to call:
- // controller_->OnChanged();
- // In the current implementation, this tells LocationBarViewMac to
- // mess around with |model_| and update |field_|. Unfortunately,
- // when I look at our peer implementations, it's not entirely clear
- // to me if this is safe. SetText() is sort of an utility method,
- // and different callers sometimes have different needs. Research
- // this issue so that it can be added safely.
-
- // TODO(shess): Also, consider whether this code couldn't just
- // manage things directly. Windows uses a series of overlaid view
- // objects to accomplish the hinting stuff that OnChanged() does, so
- // it makes sense to have it in the controller that lays those
- // things out. Mac instead pushes the support into a custom
- // text-field implementation.
-}
-
-void AutocompleteEditViewMac::SetTextAndSelectedRange(
- const std::wstring& display_text, const NSRange range) {
- SetText(display_text);
- SetSelectedRange(range);
-}
-
-void AutocompleteEditViewMac::EmphasizeURLComponents() {
- if ([field_ currentEditor]) {
- SetTextAndSelectedRange(GetText(), GetSelectedRange());
- } else {
- SetText(GetText());
- }
}
void AutocompleteEditViewMac::OnTemporaryTextMaybeChanged(
@@ -532,7 +554,8 @@ bool AutocompleteEditViewMac::OnInlineAutocompleteTextMaybeChanged(
}
DCHECK_LE(user_text_length, display_text.size());
- const NSRange range = NSMakeRange(user_text_length, display_text.size());
+ const NSRange range =
+ NSMakeRange(user_text_length, display_text.size() - user_text_length);
SetTextAndSelectedRange(display_text, range);
controller_->OnChanged();
[field_ clearUndoChain];
diff --git a/chrome/browser/cocoa/autocomplete_text_field.mm b/chrome/browser/cocoa/autocomplete_text_field.mm
index a07cac1..a4242bb 100644
--- a/chrome/browser/cocoa/autocomplete_text_field.mm
+++ b/chrome/browser/cocoa/autocomplete_text_field.mm
@@ -6,6 +6,7 @@
#include "base/logging.h"
#import "chrome/browser/cocoa/autocomplete_text_field_cell.h"
+#import "chrome/browser/cocoa/autocomplete_text_field_editor.h"
#import "chrome/browser/cocoa/browser_window_controller.h"
#import "chrome/browser/cocoa/toolbar_controller.h"
#import "chrome/browser/cocoa/url_drop_target.h"
@@ -169,17 +170,17 @@
}
- (void)setAttributedStringValue:(NSAttributedString*)aString {
- NSTextView* editor = static_cast<NSTextView*>([self currentEditor]);
+ AutocompleteTextFieldEditor* editor =
+ static_cast<AutocompleteTextFieldEditor*>([self currentEditor]);
+
if (!editor) {
[super setAttributedStringValue:aString];
} else {
- // -currentEditor is defined to return NSText*, make sure our
- // assumptions still hold, here.
- DCHECK([editor isKindOfClass:[NSTextView class]]);
+ // The type of the field editor must be AutocompleteTextFieldEditor,
+ // otherwise things won't work.
+ DCHECK([editor isKindOfClass:[AutocompleteTextFieldEditor class]]);
- NSTextStorage* textStorage = [editor textStorage];
- DCHECK(textStorage);
- [textStorage setAttributedString:aString];
+ [editor setAttributedString:aString];
}
}
@@ -253,13 +254,6 @@
}
}
-- (void)textDidChange:(NSNotification *)aNotification {
- [super textDidChange:aNotification];
- if (observer_) {
- observer_->OnDidChange();
- }
-}
-
- (void)textDidEndEditing:(NSNotification *)aNotification {
[super textDidEndEditing:aNotification];
if (observer_) {
diff --git a/chrome/browser/cocoa/autocomplete_text_field_editor.h b/chrome/browser/cocoa/autocomplete_text_field_editor.h
index 1c3ce5a..8f3c18c 100644
--- a/chrome/browser/cocoa/autocomplete_text_field_editor.h
+++ b/chrome/browser/cocoa/autocomplete_text_field_editor.h
@@ -30,6 +30,17 @@ class Profile;
Profile* profile_;
scoped_nsobject<NSCharacterSet> forbiddenCharacters_;
+
+ // Indicates if the field editor's interpretKeyEvents: method is being called.
+ // If it's YES, then we should postpone the call to the observer's
+ // OnDidChange() method after the field editor's interpretKeyEvents: method
+ // is finished, rather than calling it in textDidChange: method. Because the
+ // input method may update the marked text after inserting some text, but we
+ // need the observer be aware of the marked text as well.
+ BOOL interpretingKeyEvents_;
+
+ // Indicates if the text has been changed by key events.
+ BOOL textChangedByKeyEvents_;
}
@property(nonatomic) Profile* profile;
@@ -39,6 +50,10 @@ class Profile;
- (AutocompleteTextField*)delegate;
- (void)setDelegate:(AutocompleteTextField*)delegate;
+// Sets attributed string programatically through the field editor's text
+// storage object.
+- (void)setAttributedString:(NSAttributedString*)aString;
+
@end
@interface AutocompleteTextFieldEditor(PrivateTestMethods)
diff --git a/chrome/browser/cocoa/autocomplete_text_field_editor.mm b/chrome/browser/cocoa/autocomplete_text_field_editor.mm
index 974b346..936b013 100644
--- a/chrome/browser/cocoa/autocomplete_text_field_editor.mm
+++ b/chrome/browser/cocoa/autocomplete_text_field_editor.mm
@@ -266,4 +266,49 @@ class Extension;
[super insertText:aString];
}
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange {
+ [super setMarkedText:aString selectedRange:selRange];
+
+ // Because the AutocompleteEditViewMac class treats marked text as content,
+ // we need to treat the change to marked text as content change as well.
+ [self didChangeText];
+}
+
+- (void)interpretKeyEvents:(NSArray *)eventArray {
+ DCHECK(!interpretingKeyEvents_);
+ interpretingKeyEvents_ = YES;
+ textChangedByKeyEvents_ = NO;
+ [super interpretKeyEvents:eventArray];
+
+ AutocompleteTextFieldObserver* observer = [self observer];
+ if (textChangedByKeyEvents_ && observer)
+ observer->OnDidChange();
+
+ DCHECK(interpretingKeyEvents_);
+ interpretingKeyEvents_ = NO;
+}
+
+- (void)didChangeText {
+ [super didChangeText];
+
+ AutocompleteTextFieldObserver* observer = [self observer];
+ if (observer) {
+ if (!interpretingKeyEvents_)
+ observer->OnDidChange();
+ else
+ textChangedByKeyEvents_ = YES;
+ }
+}
+
+- (void)setAttributedString:(NSAttributedString*)aString {
+ NSTextStorage* textStorage = [self textStorage];
+ DCHECK(textStorage);
+ [textStorage setAttributedString:aString];
+
+ // The text has been changed programmatically. The observer should know
+ // this change, so setting |textChangedByKeyEvents_| to NO to
+ // prevent its OnDidChange() method from being called unnecessarily.
+ textChangedByKeyEvents_ = NO;
+}
+
@end