summaryrefslogtreecommitdiffstats
path: root/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
diff options
context:
space:
mode:
authortfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-28 20:24:00 +0000
committertfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-28 20:24:00 +0000
commit939404935277cd0b4ecbe606781297361383bff0 (patch)
treee0230f309d2a90a4ee24ff22961d5aa4c4cd8982 /chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
parent7e1bcdd086adb95c12c6abb0bb8f70a7e702e797 (diff)
downloadchromium_src-939404935277cd0b4ecbe606781297361383bff0.zip
chromium_src-939404935277cd0b4ecbe606781297361383bff0.tar.gz
chromium_src-939404935277cd0b4ecbe606781297361383bff0.tar.bz2
cocoa: Move AutocompleteEditViewMac/autocomplete_edit_view_mac.* to ui/cocoa/omnibox directory.
- Rename AutocompleteEditViewMac to OmniboxViewMac. - Move autocomplete_edit_view_mac.* to omnibox_view_mac.* BUG=80186 TEST=None R=pkasting@chromium.org Review URL: http://codereview.chromium.org/6904049 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@83387 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/autocomplete/autocomplete_edit_view_mac.mm')
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_mac.mm1125
1 files changed, 0 insertions, 1125 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
deleted file mode 100644
index 69d5afe6..0000000
--- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
+++ /dev/null
@@ -1,1125 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
-
-#include <Carbon/Carbon.h> // kVK_Return
-
-#include "app/mac/nsimage_cache.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/autocomplete/autocomplete_edit.h"
-#include "chrome/browser/autocomplete/autocomplete_match.h"
-#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
-#include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/ui/cocoa/event_utils.h"
-#include "chrome/browser/ui/toolbar/toolbar_model.h"
-#include "content/browser/tab_contents/tab_contents.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "grit/theme_resources_standard.h"
-#include "net/base/escape.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image.h"
-#include "ui/gfx/rect.h"
-
-// Focus-handling between |field_| and |model_| is a bit subtle.
-// Other platforms detect change of focus, which is inconvenient
-// without subclassing NSTextField (even with a subclass, the use of a
-// field editor may complicate things).
-//
-// |model_| doesn't actually do anything when it gains focus, it just
-// initializes. Visible activity happens only after the user edits.
-// NSTextField delegate receives messages around starting and ending
-// edits, so that suffices to catch focus changes. Since all calls
-// into |model_| start from AutocompleteEditViewMac, in the worst case
-// we can add code to sync up the sense of focus as needed.
-//
-// I've added DCHECK(IsFirstResponder()) in the places which I believe
-// should only be reachable when |field_| is being edited. If these
-// fire, it probably means someone unexpected is calling into
-// |model_|.
-//
-// Other platforms don't appear to have the sense of "key window" that
-// Mac does (I believe their fields lose focus when the window loses
-// focus). Rather than modifying focus outside the control's edit
-// scope, when the window resigns key the autocomplete popup is
-// closed. |model_| still believes it has focus, and the popup will
-// be regenerated on the user's next edit. That seems to match how
-// things work on other platforms.
-
-namespace {
-
-// TODO(shess): This is ugly, find a better way. Using it right now
-// so that I can crib from gtk and still be able to see that I'm using
-// the same values easily.
-NSColor* ColorWithRGBBytes(int rr, int gg, int bb) {
- DCHECK_LE(rr, 255);
- DCHECK_LE(bb, 255);
- DCHECK_LE(gg, 255);
- return [NSColor colorWithCalibratedRed:static_cast<float>(rr)/255.0
- green:static_cast<float>(gg)/255.0
- blue:static_cast<float>(bb)/255.0
- alpha:1.0];
-}
-
-NSColor* HostTextColor() {
- return [NSColor blackColor];
-}
-NSColor* BaseTextColor() {
- return [NSColor darkGrayColor];
-}
-NSColor* SuggestTextColor() {
- return [NSColor grayColor];
-}
-NSColor* SecureSchemeColor() {
- return ColorWithRGBBytes(0x07, 0x95, 0x00);
-}
-NSColor* SecurityErrorSchemeColor() {
- return ColorWithRGBBytes(0xa2, 0x00, 0x00);
-}
-
-// Store's the model and view state across tab switches.
-struct AutocompleteEditViewMacState {
- AutocompleteEditViewMacState(const AutocompleteEditModel::State model_state,
- const bool has_focus, const NSRange& selection)
- : model_state(model_state),
- has_focus(has_focus),
- selection(selection) {
- }
-
- const AutocompleteEditModel::State model_state;
- const bool has_focus;
- const NSRange selection;
-};
-
-// Returns a lazily initialized property bag accessor for saving our
-// state in a TabContents. When constructed |accessor| generates a
-// globally-unique id used to index into the per-tab PropertyBag used
-// to store the state data.
-PropertyAccessor<AutocompleteEditViewMacState>* GetStateAccessor() {
- static PropertyAccessor<AutocompleteEditViewMacState> accessor;
- return &accessor;
-}
-
-// Accessors for storing and getting the state from the tab.
-void StoreStateToTab(TabContents* tab,
- const AutocompleteEditViewMacState& state) {
- GetStateAccessor()->SetProperty(tab->property_bag(), state);
-}
-const AutocompleteEditViewMacState* GetStateFromTab(const TabContents* tab) {
- return GetStateAccessor()->GetProperty(tab->property_bag());
-}
-
-// Helper to make converting url_parse ranges to NSRange easier to
-// read.
-NSRange ComponentToNSRange(const url_parse::Component& component) {
- return NSMakeRange(static_cast<NSInteger>(component.begin),
- static_cast<NSInteger>(component.len));
-}
-
-} // namespace
-
-// static
-NSImage* AutocompleteEditViewMac::ImageForResource(int resource_id) {
- NSString* image_name = nil;
-
- switch(resource_id) {
- // From the autocomplete popup, or the star icon at the RHS of the
- // text field.
- case IDR_STAR: image_name = @"star.pdf"; break;
- case IDR_STAR_LIT: image_name = @"star_lit.pdf"; break;
-
- // Values from |AutocompleteMatch::TypeToIcon()|.
- case IDR_OMNIBOX_SEARCH:
- image_name = @"omnibox_search.pdf"; break;
- case IDR_OMNIBOX_HTTP:
- image_name = @"omnibox_http.pdf"; break;
- case IDR_OMNIBOX_HISTORY:
- image_name = @"omnibox_history.pdf"; break;
- case IDR_OMNIBOX_EXTENSION_APP:
- image_name = @"omnibox_extension_app.pdf"; break;
-
- // Values from |ToolbarModel::GetIcon()|.
- case IDR_OMNIBOX_HTTPS_VALID:
- image_name = @"omnibox_https_valid.pdf"; break;
- case IDR_OMNIBOX_HTTPS_WARNING:
- image_name = @"omnibox_https_warning.pdf"; break;
- case IDR_OMNIBOX_HTTPS_INVALID:
- image_name = @"omnibox_https_invalid.pdf"; break;
- }
-
- if (image_name) {
- if (NSImage* image = app::mac::GetCachedImageWithName(image_name)) {
- return image;
- } else {
- NOTREACHED()
- << "Missing image for " << base::SysNSStringToUTF8(image_name);
- }
- }
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- return rb.GetNativeImageNamed(resource_id);
-}
-
-AutocompleteEditViewMac::AutocompleteEditViewMac(
- AutocompleteEditController* controller,
- ToolbarModel* toolbar_model,
- Profile* profile,
- CommandUpdater* command_updater,
- AutocompleteTextField* field)
- : model_(new AutocompleteEditModel(this, controller, profile)),
- popup_view_(new AutocompletePopupViewMac(this, model_.get(), profile,
- field)),
- controller_(controller),
- toolbar_model_(toolbar_model),
- command_updater_(command_updater),
- field_(field),
- suggest_text_length_(0),
- delete_was_pressed_(false),
- delete_at_end_pressed_(false),
- line_height_(0) {
- DCHECK(controller);
- DCHECK(toolbar_model);
- DCHECK(profile);
- DCHECK(command_updater);
- DCHECK(field);
- [field_ setObserver:this];
-
- // Needed so that editing doesn't lose the styling.
- [field_ setAllowsEditingTextAttributes:YES];
-
- // Get the appropriate line height for the font that we use.
- scoped_nsobject<NSLayoutManager>
- layoutManager([[NSLayoutManager alloc] init]);
- [layoutManager setUsesScreenFonts:YES];
- line_height_ = [layoutManager defaultLineHeightForFont:GetFieldFont()];
- DCHECK_GT(line_height_, 0);
-}
-
-AutocompleteEditViewMac::~AutocompleteEditViewMac() {
- // Destroy popup view before this object in case it tries to call us
- // back in the destructor. Likewise for destroying the model before
- // this object.
- popup_view_.reset();
- model_.reset();
-
- // Disconnect from |field_|, it outlives this object.
- [field_ setObserver:NULL];
-}
-
-AutocompleteEditModel* AutocompleteEditViewMac::model() {
- return model_.get();
-}
-
-const AutocompleteEditModel* AutocompleteEditViewMac::model() const {
- return model_.get();
-}
-
-void AutocompleteEditViewMac::SaveStateToTab(TabContents* tab) {
- DCHECK(tab);
-
- const bool hasFocus = [field_ currentEditor] ? true : false;
-
- NSRange range;
- if (hasFocus) {
- range = GetSelectedRange();
- } else {
- // If we are not focussed, there is no selection. Manufacture
- // something reasonable in case it starts to matter in the future.
- range = NSMakeRange(0, GetTextLength());
- }
-
- AutocompleteEditViewMacState state(model_->GetStateForTabSwitch(),
- hasFocus, range);
- StoreStateToTab(tab, state);
-}
-
-void AutocompleteEditViewMac::Update(
- const TabContents* tab_for_state_restoring) {
- // TODO(shess): It seems like if the tab is non-NULL, then this code
- // shouldn't need to be called at all. When coded that way, I find
- // that the field isn't always updated correctly. Figure out why
- // this is. Maybe this method should be refactored into more
- // specific cases.
- const bool user_visible =
- model_->UpdatePermanentText(WideToUTF16Hack(toolbar_model_->GetText()));
-
- if (tab_for_state_restoring) {
- RevertAll();
-
- const AutocompleteEditViewMacState* state =
- GetStateFromTab(tab_for_state_restoring);
- if (state) {
- // Should restore the user's text via SetUserText().
- model_->RestoreState(state->model_state);
-
- // Restore focus and selection if they were present when the tab
- // was switched away.
- if (state->has_focus) {
- // TODO(shess): Unfortunately, there is no safe way to update
- // this because TabStripController -selectTabWithContents:* is
- // also messing with focus. Both parties need to agree to
- // store existing state before anyone tries to setup the new
- // state. Anyhow, it would look something like this.
-#if 0
- [[field_ window] makeFirstResponder:field_];
- [[field_ currentEditor] setSelectedRange:state->selection];
-#endif
- }
- }
- } else if (user_visible) {
- // Restore everything to the baseline look.
- RevertAll();
- // TODO(shess): Figure out how this case is used, to make sure
- // we're getting the selection and popup right.
-
- } else {
- // TODO(shess): This corresponds to _win and _gtk, except those
- // guard it with a test for whether the security level changed.
- // But AFAICT, that can only change if the text changed, and that
- // code compares the toolbar_model_ security level with the local
- // security level. Dig in and figure out why this isn't a no-op
- // that should go away.
- EmphasizeURLComponents();
- }
-}
-
-void AutocompleteEditViewMac::OpenURL(const GURL& url,
- WindowOpenDisposition disposition,
- PageTransition::Type transition,
- const GURL& alternate_nav_url,
- size_t selected_line,
- const string16& keyword) {
- // TODO(shess): Why is the caller passing an invalid url in the
- // first place? Make sure that case isn't being dropped on the
- // floor.
- if (!url.is_valid()) {
- return;
- }
-
- model_->OpenURL(url, disposition, transition, alternate_nav_url,
- selected_line, keyword);
-}
-
-string16 AutocompleteEditViewMac::GetText() const {
- return base::SysNSStringToUTF16(GetNonSuggestTextSubstring());
-}
-
-bool AutocompleteEditViewMac::IsEditingOrEmpty() const {
- return model_->user_input_in_progress() || !GetTextLength();
-}
-
-int AutocompleteEditViewMac::GetIcon() const {
- return IsEditingOrEmpty() ?
- AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) :
- toolbar_model_->GetIcon();
-}
-
-void AutocompleteEditViewMac::SetUserText(const string16& text) {
- SetUserText(text, text, true);
-}
-
-void AutocompleteEditViewMac::SetUserText(const string16& text,
- const string16& display_text,
- bool update_popup) {
- model_->SetUserText(text);
- // TODO(shess): TODO below from gtk.
- // TODO(deanm): something about selection / focus change here.
- SetText(display_text);
- if (update_popup) {
- UpdatePopup();
- }
- model_->OnChanged();
-}
-
-NSRange AutocompleteEditViewMac::GetSelectedRange() const {
- return [[field_ currentEditor] selectedRange];
-}
-
-NSRange AutocompleteEditViewMac::GetMarkedRange() const {
- DCHECK([field_ currentEditor]);
- return [(NSTextView*)[field_ currentEditor] markedRange];
-}
-
-void AutocompleteEditViewMac::SetSelectedRange(const NSRange range) {
- // This can be called when we don't have focus. For instance, when
- // the user clicks the "Go" button.
- if (model_->has_focus()) {
- // TODO(shess): If |model_| thinks we have focus, this should not
- // be necessary. Try to convert to DCHECK(IsFirstResponder()).
- if (![field_ currentEditor]) {
- [[field_ window] makeFirstResponder:field_];
- }
-
- // TODO(shess): What if it didn't get first responder, and there is
- // no field editor? This will do nothing. Well, at least it won't
- // crash. Think of something more productive to do, or prove that
- // it cannot occur and DCHECK appropriately.
- [[field_ currentEditor] setSelectedRange:range];
- }
-}
-
-void AutocompleteEditViewMac::SetWindowTextAndCaretPos(const string16& text,
- size_t caret_pos) {
- DCHECK_LE(caret_pos, text.size());
- SetTextAndSelectedRange(text, NSMakeRange(caret_pos, caret_pos));
-}
-
-void AutocompleteEditViewMac::SetForcedQuery() {
- // We need to do this first, else |SetSelectedRange()| won't work.
- FocusLocation(true);
-
- const string16 current_text(GetText());
- const size_t start = current_text.find_first_not_of(kWhitespaceUTF16);
- if (start == string16::npos || (current_text[start] != '?')) {
- SetUserText(ASCIIToUTF16("?"));
- } else {
- NSRange range = NSMakeRange(start + 1, current_text.size() - start - 1);
- [[field_ currentEditor] setSelectedRange:range];
- }
-}
-
-bool AutocompleteEditViewMac::IsSelectAll() {
- if (![field_ currentEditor])
- return true;
- const NSRange all_range = NSMakeRange(0, GetTextLength());
- return NSEqualRanges(all_range, GetSelectedRange());
-}
-
-bool AutocompleteEditViewMac::DeleteAtEndPressed() {
- return delete_at_end_pressed_;
-}
-
-void AutocompleteEditViewMac::GetSelectionBounds(string16::size_type* start,
- string16::size_type* end) {
- if (![field_ currentEditor]) {
- *start = *end = 0;
- return;
- }
-
- const NSRange selected_range = GetSelectedRange();
- *start = static_cast<size_t>(selected_range.location);
- *end = static_cast<size_t>(NSMaxRange(selected_range));
-}
-
-void AutocompleteEditViewMac::SelectAll(bool reversed) {
- // TODO(shess): Figure out what |reversed| implies. The gtk version
- // has it imply inverting the selection front to back, but I don't
- // even know if that makes sense for Mac.
-
- // TODO(shess): Verify that we should be stealing focus at this
- // point.
- SetSelectedRange(NSMakeRange(0, GetTextLength()));
-}
-
-void AutocompleteEditViewMac::RevertAll() {
- ClosePopup();
- model_->Revert();
- model_->OnChanged();
- [field_ clearUndoChain];
-}
-
-void AutocompleteEditViewMac::UpdatePopup() {
- model_->SetInputInProgress(true);
- if (!model_->has_focus())
- return;
-
- // Comment copied from OmniboxViewWin::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 = IsImeComposing();
- NSTextView* editor = (NSTextView*)[field_ currentEditor];
- if (editor) {
- if (NSMaxRange([editor selectedRange]) <
- [[editor textStorage] length] - suggest_text_length_)
- prevent_inline_autocomplete = true;
- }
-
- model_->StartAutocomplete([editor selectedRange].length != 0,
- prevent_inline_autocomplete);
-}
-
-void AutocompleteEditViewMac::ClosePopup() {
- model_->StopAutocomplete();
-}
-
-void AutocompleteEditViewMac::SetFocus() {
-}
-
-void AutocompleteEditViewMac::SetText(const string16& display_text) {
- // If we are setting the text directly, there cannot be any suggest text.
- suggest_text_length_ = 0;
- SetTextInternal(display_text);
-}
-
-void AutocompleteEditViewMac::SetTextInternal(
- const string16& display_text) {
- NSString* ss = base::SysUTF16ToNSString(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:
- // model_->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. SetTextInternal() 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 string16& display_text, const NSRange range) {
- SetText(display_text);
- SetSelectedRange(range);
-}
-
-NSString* AutocompleteEditViewMac::GetNonSuggestTextSubstring() const {
- NSString* text = [field_ stringValue];
- if (suggest_text_length_ > 0) {
- NSUInteger length = [text length];
-
- DCHECK_LE(suggest_text_length_, length);
- text = [text substringToIndex:(length - suggest_text_length_)];
- }
- return text;
-}
-
-NSString* AutocompleteEditViewMac::GetSuggestTextSubstring() const {
- if (suggest_text_length_ == 0)
- return nil;
-
- NSString* text = [field_ stringValue];
- NSUInteger length = [text length];
- DCHECK_LE(suggest_text_length_, length);
- return [text substringFromIndex:(length - suggest_text_length_)];
-}
-
-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];
-
- // Clear the existing attributes from the text storage, then
- // overlay the appropriate Omnibox attributes.
- [storage setAttributes:[NSDictionary dictionary]
- range:NSMakeRange(0, [storage length])];
- ApplyTextAttributes(GetText(), storage);
-
- [storage endEditing];
- } else {
- SetText(GetText());
- }
-}
-
-void AutocompleteEditViewMac::ApplyTextAttributes(
- const string16& display_text, NSMutableAttributedString* as) {
- [as addAttribute:NSFontAttributeName value:GetFieldFont()
- range:NSMakeRange(0, [as length])];
-
- // Make a paragraph style locking in the standard line height as the maximum,
- // otherwise the baseline may shift "downwards".
- scoped_nsobject<NSMutableParagraphStyle>
- paragraph_style([[NSMutableParagraphStyle alloc] init]);
- [paragraph_style setMaximumLineHeight:line_height_];
- [as addAttribute:NSParagraphStyleAttributeName value:paragraph_style
- range:NSMakeRange(0, [as length])];
-
- // Grey out the suggest text.
- [as addAttribute:NSForegroundColorAttributeName value:SuggestTextColor()
- range:NSMakeRange([as length] - suggest_text_length_,
- suggest_text_length_)];
-
- url_parse::Component scheme, host;
- AutocompleteInput::ParseForEmphasizeComponents(
- display_text, model_->GetDesiredTLD(), &scheme, &host);
- const bool emphasize = model_->CurrentTextIsURL() && (host.len > 0);
- if (emphasize) {
- [as addAttribute:NSForegroundColorAttributeName value:BaseTextColor()
- range:NSMakeRange(0, [as length])];
-
- [as addAttribute:NSForegroundColorAttributeName value:HostTextColor()
- range:ComponentToNSRange(host)];
- }
-
- // TODO(shess): GTK has this as a member var, figure out why.
- // [Could it be to not change if no change? If so, I'm guessing
- // AppKit may already handle that.]
- const ToolbarModel::SecurityLevel security_level =
- toolbar_model_->GetSecurityLevel();
-
- // Emphasize the scheme for security UI display purposes (if necessary).
- if (!model_->user_input_in_progress() && scheme.is_nonempty() &&
- (security_level != ToolbarModel::NONE)) {
- NSColor* color;
- if (security_level == ToolbarModel::EV_SECURE ||
- security_level == ToolbarModel::SECURE) {
- color = SecureSchemeColor();
- } else if (security_level == ToolbarModel::SECURITY_ERROR) {
- color = SecurityErrorSchemeColor();
- // Add a strikethrough through the scheme.
- [as addAttribute:NSStrikethroughStyleAttributeName
- value:[NSNumber numberWithInt:NSUnderlineStyleSingle]
- range:ComponentToNSRange(scheme)];
- } else if (security_level == ToolbarModel::SECURITY_WARNING) {
- color = BaseTextColor();
- } else {
- NOTREACHED();
- color = BaseTextColor();
- }
- [as addAttribute:NSForegroundColorAttributeName value:color
- range:ComponentToNSRange(scheme)];
- }
-}
-
-void AutocompleteEditViewMac::OnTemporaryTextMaybeChanged(
- const string16& display_text, bool save_original_selection) {
- if (save_original_selection)
- saved_temporary_selection_ = GetSelectedRange();
-
- suggest_text_length_ = 0;
- SetWindowTextAndCaretPos(display_text, display_text.size());
- model_->OnChanged();
- [field_ clearUndoChain];
-}
-
-void AutocompleteEditViewMac::OnStartingIME() {
- // Reset the suggest text just before starting an IME composition session,
- // otherwise the IME composition may be interrupted when the suggest text
- // gets reset by the IME composition change.
- SetInstantSuggestion(string16(), false);
-}
-
-bool AutocompleteEditViewMac::OnInlineAutocompleteTextMaybeChanged(
- const string16& display_text, size_t user_text_length) {
- // TODO(shess): Make sure that this actually works. The round trip
- // to native form and back may mean that it's the same but not the
- // same.
- if (display_text == GetText())
- return false;
-
- DCHECK_LE(user_text_length, display_text.size());
- const NSRange range =
- NSMakeRange(user_text_length, display_text.size() - user_text_length);
- SetTextAndSelectedRange(display_text, range);
- model_->OnChanged();
- [field_ clearUndoChain];
-
- return true;
-}
-
-void AutocompleteEditViewMac::OnRevertTemporaryText() {
- SetSelectedRange(saved_temporary_selection_);
-}
-
-bool AutocompleteEditViewMac::IsFirstResponder() const {
- return [field_ currentEditor] != nil ? true : false;
-}
-
-void AutocompleteEditViewMac::OnBeforePossibleChange() {
- // We should only arrive here when the field is focussed.
- DCHECK(IsFirstResponder());
-
- selection_before_change_ = GetSelectedRange();
- text_before_change_ = GetText();
- marked_range_before_change_ = GetMarkedRange();
-}
-
-bool AutocompleteEditViewMac::OnAfterPossibleChange() {
- // We should only arrive here when the field is focussed.
- DCHECK(IsFirstResponder());
-
- const NSRange new_selection(GetSelectedRange());
- const string16 new_text(GetText());
- const size_t length = new_text.length();
-
- const bool selection_differs =
- (new_selection.length || selection_before_change_.length) &&
- !NSEqualRanges(new_selection, selection_before_change_);
- const bool at_end_of_edit = (length == new_selection.location);
- const bool text_differs = (new_text != text_before_change_) ||
- !NSEqualRanges(marked_range_before_change_, GetMarkedRange());
-
- // When the user has deleted text, we don't allow inline
- // autocomplete. This is assumed if the text has gotten shorter AND
- // the selection has shifted towards the front of the text. During
- // normal typing the text will almost always be shorter (as the new
- // input replaces the autocomplete suggestion), but in that case the
- // selection point will have moved towards the end of the text.
- // TODO(shess): In our implementation, we can catch -deleteBackward:
- // and other methods to provide positive knowledge that a delete
- // occured, rather than intuiting it from context. Consider whether
- // that would be a stronger approach.
- const bool just_deleted_text =
- (length < text_before_change_.length() &&
- new_selection.location <= selection_before_change_.location);
-
- delete_at_end_pressed_ = false;
-
- const bool something_changed = model_->OnAfterPossibleChange(
- new_text, new_selection.location, NSMaxRange(new_selection),
- selection_differs, text_differs, just_deleted_text,
- !IsImeComposing());
-
- if (delete_was_pressed_ && at_end_of_edit)
- delete_at_end_pressed_ = true;
-
- // Restyle in case the user changed something.
- // TODO(shess): I believe there are multiple-redraw cases, here.
- // Linux watches for something_changed && text_differs, but that
- // fails for us in case you copy the URL and paste the identical URL
- // back (we'll lose the styling).
- EmphasizeURLComponents();
- model_->OnChanged();
-
- delete_was_pressed_ = false;
-
- return something_changed;
-}
-
-gfx::NativeView AutocompleteEditViewMac::GetNativeView() const {
- return field_;
-}
-
-CommandUpdater* AutocompleteEditViewMac::GetCommandUpdater() {
- return command_updater_;
-}
-
-void AutocompleteEditViewMac::SetInstantSuggestion(
- const string16& suggest_text,
- bool animate_to_complete) {
- NSString* text = GetNonSuggestTextSubstring();
- bool needs_update = (suggest_text_length_ > 0);
-
- // Append the new suggest text.
- suggest_text_length_ = suggest_text.length();
- if (suggest_text_length_ > 0) {
- text = [text stringByAppendingString:base::SysUTF16ToNSString(
- suggest_text)];
- needs_update = true;
- }
-
- if (needs_update) {
- NSRange current_range = GetSelectedRange();
- SetTextInternal(base::SysNSStringToUTF16(text));
- if (NSMaxRange(current_range) <= [text length] - suggest_text_length_)
- SetSelectedRange(current_range);
- else
- SetSelectedRange(NSMakeRange([text length] - suggest_text_length_, 0));
- }
-}
-
-string16 AutocompleteEditViewMac::GetInstantSuggestion() const {
- return suggest_text_length_ ?
- base::SysNSStringToUTF16(GetSuggestTextSubstring()) : string16();
-}
-
-int AutocompleteEditViewMac::TextWidth() const {
- // Not used on mac.
- NOTREACHED();
- return 0;
-}
-
-bool AutocompleteEditViewMac::IsImeComposing() const {
- return [(NSTextView*)[field_ currentEditor] hasMarkedText];
-}
-
-void AutocompleteEditViewMac::OnDidBeginEditing() {
- // We should only arrive here when the field is focussed.
- DCHECK([field_ currentEditor]);
-}
-
-void AutocompleteEditViewMac::OnBeforeChange() {
- // Capture the current state.
- OnBeforePossibleChange();
-}
-
-void AutocompleteEditViewMac::OnDidChange() {
- // Figure out what changed and notify the model_.
- OnAfterPossibleChange();
-}
-
-void AutocompleteEditViewMac::OnDidEndEditing() {
- ClosePopup();
-}
-
-bool AutocompleteEditViewMac::OnDoCommandBySelector(SEL cmd) {
- // We should only arrive here when the field is focussed.
- DCHECK(IsFirstResponder());
-
- if (cmd != @selector(moveRight:) &&
- cmd != @selector(insertTab:) &&
- cmd != @selector(insertTabIgnoringFieldEditor:)) {
- // Reset the suggest text for any change other than key right or tab.
- // TODO(rohitrao): This is here to prevent complications when editing text.
- // See if this can be removed.
- SetInstantSuggestion(string16(), false);
- }
-
- if (cmd == @selector(deleteForward:))
- delete_was_pressed_ = true;
-
- // Don't intercept up/down-arrow if the popup isn't open.
- if (popup_view_->IsOpen()) {
- if (cmd == @selector(moveDown:)) {
- model_->OnUpOrDownKeyPressed(1);
- return true;
- }
-
- if (cmd == @selector(moveUp:)) {
- model_->OnUpOrDownKeyPressed(-1);
- return true;
- }
- }
-
- if (cmd == @selector(moveRight:)) {
- // Only commit suggested text if the cursor is all the way to the right and
- // there is no selection.
- if (suggest_text_length_ > 0 && IsCaretAtEnd()) {
- model_->CommitSuggestedText(true);
- return true;
- }
- }
-
- if (cmd == @selector(scrollPageDown:)) {
- model_->OnUpOrDownKeyPressed(model_->result().size());
- return true;
- }
-
- if (cmd == @selector(scrollPageUp:)) {
- model_->OnUpOrDownKeyPressed(-model_->result().size());
- return true;
- }
-
- if (cmd == @selector(cancelOperation:)) {
- return model_->OnEscapeKeyPressed();
- }
-
- if (cmd == @selector(insertTab:) ||
- cmd == @selector(insertTabIgnoringFieldEditor:)) {
- if (model_->is_keyword_hint())
- return model_->AcceptKeyword();
-
- if (suggest_text_length_ > 0) {
- model_->CommitSuggestedText(true);
- return true;
- }
-
- if (!IsCaretAtEnd()) {
- PlaceCaretAt(GetTextLength());
- // OnDidChange() will not be triggered when setting selected range in this
- // method, so we need to call it explicitly.
- OnDidChange();
- return true;
- }
-
- if (model_->AcceptCurrentInstantPreview())
- return true;
- }
-
- // |-noop:| is sent when the user presses Cmd+Return. Override the no-op
- // behavior with the proper WindowOpenDisposition.
- NSEvent* event = [NSApp currentEvent];
- if (cmd == @selector(insertNewline:) ||
- (cmd == @selector(noop:) && [event keyCode] == kVK_Return)) {
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEvent(event);
- model_->AcceptInput(disposition, false);
- // Opening a URL in a background tab should also revert the omnibox contents
- // to their original state. We cannot do a blanket revert in OpenURL()
- // because middle-clicks also open in a new background tab, but those should
- // not revert the omnibox text.
- RevertAll();
- return true;
- }
-
- // Option-Return
- if (cmd == @selector(insertNewlineIgnoringFieldEditor:)) {
- model_->AcceptInput(NEW_FOREGROUND_TAB, false);
- return true;
- }
-
- // When the user does Control-Enter, the existing content has "www."
- // prepended and ".com" appended. |model_| should already have
- // received notification when the Control key was depressed, but it
- // is safe to tell it twice.
- if (cmd == @selector(insertLineBreak:)) {
- OnControlKeyChanged(true);
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
- model_->AcceptInput(disposition, false);
- return true;
- }
-
- if (cmd == @selector(deleteBackward:)) {
- if (OnBackspacePressed()) {
- return true;
- }
- }
-
- if (cmd == @selector(deleteForward:)) {
- const NSUInteger modifiers = [[NSApp currentEvent] modifierFlags];
- if ((modifiers & NSShiftKeyMask) != 0) {
- if (model_->popup_model()->IsOpen()) {
- model_->popup_model()->TryDeletingCurrentItem();
- return true;
- }
- }
- }
-
- return false;
-}
-
-void AutocompleteEditViewMac::OnSetFocus(bool control_down) {
- model_->OnSetFocus(control_down);
- controller_->OnSetFocus();
-}
-
-void AutocompleteEditViewMac::OnKillFocus() {
- // Tell the model to reset itself.
- model_->OnWillKillFocus(NULL);
- model_->OnKillFocus();
- controller_->OnKillFocus();
-}
-
-bool AutocompleteEditViewMac::CanCopy() {
- const NSRange selection = GetSelectedRange();
- return selection.length > 0;
-}
-
-void AutocompleteEditViewMac::CopyToPasteboard(NSPasteboard* pb) {
- DCHECK(CanCopy());
-
- const NSRange selection = GetSelectedRange();
- string16 text = base::SysNSStringToUTF16(
- [[field_ stringValue] substringWithRange:selection]);
-
- GURL url;
- bool write_url = false;
- model_->AdjustTextForCopy(selection.location, IsSelectAll(), &text, &url,
- &write_url);
-
- NSString* nstext = base::SysUTF16ToNSString(text);
- [pb declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
- [pb setString:nstext forType:NSStringPboardType];
-
- if (write_url) {
- [pb declareURLPasteboardWithAdditionalTypes:[NSArray array] owner:nil];
- [pb setDataForURL:base::SysUTF8ToNSString(url.spec()) title:nstext];
- }
-}
-
-void AutocompleteEditViewMac::OnPaste() {
- // This code currently expects |field_| to be focussed.
- DCHECK([field_ currentEditor]);
-
- string16 text = GetClipboardText(g_browser_process->clipboard());
- if (text.empty()) {
- return;
- }
- NSString* s = base::SysUTF16ToNSString(text);
-
- // -shouldChangeTextInRange:* and -didChangeText are documented in
- // NSTextView as things you need to do if you write additional
- // user-initiated editing functions. They cause the appropriate
- // delegate methods to be called.
- // TODO(shess): It would be nice to separate the Cocoa-specific code
- // from the Chrome-specific code.
- NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
- const NSRange selectedRange = GetSelectedRange();
- if ([editor shouldChangeTextInRange:selectedRange replacementString:s]) {
- // Record this paste, so we can do different behavior.
- model_->on_paste();
-
- // Force a Paste operation to trigger the text_changed code in
- // OnAfterPossibleChange(), even if identical contents are pasted
- // into the text box.
- text_before_change_.clear();
-
- [editor replaceCharactersInRange:selectedRange withString:s];
- [editor didChangeText];
- }
-}
-
-bool AutocompleteEditViewMac::CanPasteAndGo() {
- return
- model_->CanPasteAndGo(GetClipboardText(g_browser_process->clipboard()));
-}
-
-int AutocompleteEditViewMac::GetPasteActionStringId() {
- DCHECK(CanPasteAndGo());
-
- // Use PASTE_AND_SEARCH as the default fallback (although the DCHECK above
- // should never trigger).
- if (!model_->is_paste_and_search())
- return IDS_PASTE_AND_GO;
- else
- return IDS_PASTE_AND_SEARCH;
-}
-
-void AutocompleteEditViewMac::OnPasteAndGo() {
- if (CanPasteAndGo())
- model_->PasteAndGo();
-}
-
-void AutocompleteEditViewMac::OnFrameChanged() {
- // TODO(shess): UpdatePopupAppearance() is called frequently, so it
- // should be really cheap, but in this case we could probably make
- // things even cheaper by refactoring between the popup-placement
- // code and the matrix-population code.
- popup_view_->UpdatePopupAppearance();
- model_->PopupBoundsChangedTo(popup_view_->GetTargetBounds());
-
- // Give controller a chance to rearrange decorations.
- model_->OnChanged();
-}
-
-bool AutocompleteEditViewMac::OnBackspacePressed() {
- // Don't intercept if not in keyword search mode.
- if (model_->is_keyword_hint() || model_->keyword().empty()) {
- return false;
- }
-
- // Don't intercept if there is a selection, or the cursor isn't at
- // the leftmost position.
- const NSRange selection = GetSelectedRange();
- if (selection.length > 0 || selection.location > 0) {
- return false;
- }
-
- // We're showing a keyword and the user pressed backspace at the
- // beginning of the text. Delete the selected keyword.
- model_->ClearKeyword(GetText());
- return true;
-}
-
-NSRange AutocompleteEditViewMac::SelectionRangeForProposedRange(
- NSRange proposed_range) {
- // Should never call this function unless editing is in progress.
- DCHECK([field_ currentEditor]);
-
- if (![field_ currentEditor])
- return proposed_range;
-
- // Do not use [field_ stringValue] here, as that forces a sync between the
- // field and the editor. This sync will end up setting the selection, which
- // in turn calls this method, leading to an infinite loop. Instead, retrieve
- // the current string value directly from the editor.
- size_t text_length = [[[field_ currentEditor] string] length];
-
- // Cannot select suggested text.
- size_t max = text_length - suggest_text_length_;
- NSUInteger start = proposed_range.location;
- NSUInteger end = proposed_range.location + proposed_range.length;
-
- if (start > max)
- start = max;
-
- if (end > max)
- end = max;
-
- return NSMakeRange(start, end - start);
-}
-
-void AutocompleteEditViewMac::OnControlKeyChanged(bool pressed) {
- model_->OnControlKeyChanged(pressed);
-}
-
-void AutocompleteEditViewMac::FocusLocation(bool select_all) {
- if ([field_ isEditable]) {
- // If the text field has a field editor, it's the first responder, meaning
- // that it's already focused. makeFirstResponder: will select all, so only
- // call it if this behavior is desired.
- if (select_all || ![field_ currentEditor])
- [[field_ window] makeFirstResponder:field_];
- DCHECK_EQ([field_ currentEditor], [[field_ window] firstResponder]);
- }
-}
-
-// TODO(shess): Copied from autocomplete_edit_view_win.cc. Could this
-// be pushed into the model?
-string16 AutocompleteEditViewMac::GetClipboardText(
- ui::Clipboard* clipboard) {
- // autocomplete_edit_view_win.cc assumes this can never happen, we
- // will too.
- DCHECK(clipboard);
-
- if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(),
- ui::Clipboard::BUFFER_STANDARD)) {
- string16 text16;
- clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &text16);
-
- // Note: Unlike in the find popup and textfield view, here we completely
- // remove whitespace strings containing newlines. We assume users are
- // most likely pasting in URLs that may have been split into multiple
- // lines in terminals, email programs, etc., and so linebreaks indicate
- // completely bogus whitespace that would just cause the input to be
- // invalid.
- return CollapseWhitespace(text16, true);
- }
-
- // Try bookmark format.
- //
- // It is tempting to try bookmark format first, but the URL we get out of a
- // bookmark has been cannonicalized via GURL. This means if a user copies
- // and pastes from the URL bar to itself, the text will get fixed up and
- // cannonicalized, which is not what the user expects. By pasting in this
- // order, we are sure to paste what the user copied.
- if (clipboard->IsFormatAvailable(ui::Clipboard::GetUrlWFormatType(),
- ui::Clipboard::BUFFER_STANDARD)) {
- std::string url_str;
- clipboard->ReadBookmark(NULL, &url_str);
- // pass resulting url string through GURL to normalize
- GURL url(url_str);
- if (url.is_valid()) {
- return UTF8ToUTF16(url.spec());
- }
- }
-
- return string16();
-}
-
-// static
-NSFont* AutocompleteEditViewMac::GetFieldFont() {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- return rb.GetFont(ResourceBundle::BaseFont).GetNativeFont();
-}
-
-NSUInteger AutocompleteEditViewMac::GetTextLength() const {
- return ([field_ currentEditor] ?
- [[[field_ currentEditor] string] length] :
- [[field_ stringValue] length]) - suggest_text_length_;
-}
-
-void AutocompleteEditViewMac::PlaceCaretAt(NSUInteger pos) {
- DCHECK(pos <= GetTextLength());
- SetSelectedRange(NSMakeRange(pos, pos));
-}
-
-bool AutocompleteEditViewMac::IsCaretAtEnd() const {
- const NSRange selection = GetSelectedRange();
- return selection.length == 0 && selection.location == GetTextLength();
-}