Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/ui/cocoa/omnibox/omnibox_view_mac.h" | 5 #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" |
| 6 | 6 |
| 7 #include <Carbon/Carbon.h> // kVK_Return | 7 #include <Carbon/Carbon.h> // kVK_Return |
| 8 | 8 |
| 9 #include "base/property_bag.h" | 9 #include "base/property_bag.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 132 NSImage* OmniboxViewMac::ImageForResource(int resource_id) { | 132 NSImage* OmniboxViewMac::ImageForResource(int resource_id) { |
| 133 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 133 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 134 return rb.GetNativeImageNamed(resource_id); | 134 return rb.GetNativeImageNamed(resource_id); |
| 135 } | 135 } |
| 136 | 136 |
| 137 OmniboxViewMac::OmniboxViewMac(OmniboxEditController* controller, | 137 OmniboxViewMac::OmniboxViewMac(OmniboxEditController* controller, |
| 138 ToolbarModel* toolbar_model, | 138 ToolbarModel* toolbar_model, |
| 139 Profile* profile, | 139 Profile* profile, |
| 140 CommandUpdater* command_updater, | 140 CommandUpdater* command_updater, |
| 141 AutocompleteTextField* field) | 141 AutocompleteTextField* field) |
| 142 : model_(new OmniboxEditModel(this, controller, profile)), | 142 : OmniboxView(profile, controller, toolbar_model, command_updater), |
| 143 popup_view_(new OmniboxPopupViewMac(this, model_.get(), field)), | 143 popup_view_(new OmniboxPopupViewMac(this, model_.get(), field)), |
| 144 controller_(controller), | |
| 145 toolbar_model_(toolbar_model), | |
| 146 command_updater_(command_updater), | |
| 147 field_(field), | 144 field_(field), |
| 148 suggest_text_length_(0), | 145 suggest_text_length_(0), |
| 149 delete_was_pressed_(false), | 146 delete_was_pressed_(false), |
| 150 delete_at_end_pressed_(false), | 147 delete_at_end_pressed_(false), |
| 151 line_height_(0) { | 148 line_height_(0) { |
| 152 DCHECK(controller); | 149 DCHECK(controller); |
| 153 DCHECK(toolbar_model); | 150 DCHECK(toolbar_model); |
| 154 DCHECK(profile); | 151 DCHECK(profile); |
| 155 DCHECK(command_updater); | 152 DCHECK(command_updater); |
| 156 DCHECK(field); | 153 DCHECK(field); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 171 // Destroy popup view before this object in case it tries to call us | 168 // Destroy popup view before this object in case it tries to call us |
| 172 // back in the destructor. Likewise for destroying the model before | 169 // back in the destructor. Likewise for destroying the model before |
| 173 // this object. | 170 // this object. |
| 174 popup_view_.reset(); | 171 popup_view_.reset(); |
| 175 model_.reset(); | 172 model_.reset(); |
| 176 | 173 |
| 177 // Disconnect from |field_|, it outlives this object. | 174 // Disconnect from |field_|, it outlives this object. |
| 178 [field_ setObserver:NULL]; | 175 [field_ setObserver:NULL]; |
| 179 } | 176 } |
| 180 | 177 |
| 181 OmniboxEditModel* OmniboxViewMac::model() { | |
| 182 return model_.get(); | |
| 183 } | |
| 184 | |
| 185 const OmniboxEditModel* OmniboxViewMac::model() const { | |
| 186 return model_.get(); | |
| 187 } | |
| 188 | |
| 189 void OmniboxViewMac::SaveStateToTab(WebContents* tab) { | 178 void OmniboxViewMac::SaveStateToTab(WebContents* tab) { |
| 190 DCHECK(tab); | 179 DCHECK(tab); |
| 191 | 180 |
| 192 const bool hasFocus = [field_ currentEditor] ? true : false; | 181 const bool hasFocus = [field_ currentEditor] ? true : false; |
| 193 | 182 |
| 194 NSRange range; | 183 NSRange range; |
| 195 if (hasFocus) { | 184 if (hasFocus) { |
| 196 range = GetSelectedRange(); | 185 range = GetSelectedRange(); |
| 197 } else { | 186 } else { |
| 198 // If we are not focussed, there is no selection. Manufacture | 187 // If we are not focussed, there is no selection. Manufacture |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 244 // TODO(shess): This corresponds to _win and _gtk, except those | 233 // TODO(shess): This corresponds to _win and _gtk, except those |
| 245 // guard it with a test for whether the security level changed. | 234 // guard it with a test for whether the security level changed. |
| 246 // But AFAICT, that can only change if the text changed, and that | 235 // But AFAICT, that can only change if the text changed, and that |
| 247 // code compares the toolbar_model_ security level with the local | 236 // code compares the toolbar_model_ security level with the local |
| 248 // security level. Dig in and figure out why this isn't a no-op | 237 // security level. Dig in and figure out why this isn't a no-op |
| 249 // that should go away. | 238 // that should go away. |
| 250 EmphasizeURLComponents(); | 239 EmphasizeURLComponents(); |
| 251 } | 240 } |
| 252 } | 241 } |
| 253 | 242 |
| 254 void OmniboxViewMac::OpenMatch(const AutocompleteMatch& match, | |
| 255 WindowOpenDisposition disposition, | |
| 256 const GURL& alternate_nav_url, | |
| 257 size_t selected_line) { | |
| 258 // TODO(shess): Why is the caller passing an invalid url in the | |
| 259 // first place? Make sure that case isn't being dropped on the | |
| 260 // floor. | |
| 261 if (!match.destination_url.is_valid()) { | |
| 262 return; | |
| 263 } | |
| 264 | |
| 265 model_->OpenMatch(match, disposition, alternate_nav_url, selected_line); | |
| 266 } | |
| 267 | |
| 268 string16 OmniboxViewMac::GetText() const { | 243 string16 OmniboxViewMac::GetText() const { |
| 269 return base::SysNSStringToUTF16(GetNonSuggestTextSubstring()); | 244 return base::SysNSStringToUTF16(GetNonSuggestTextSubstring()); |
| 270 } | 245 } |
| 271 | 246 |
| 272 bool OmniboxViewMac::IsEditingOrEmpty() const { | |
| 273 return model_->user_input_in_progress() || !GetTextLength(); | |
| 274 } | |
| 275 | |
| 276 int OmniboxViewMac::GetIcon() const { | |
| 277 return IsEditingOrEmpty() ? | |
| 278 AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) : | |
| 279 toolbar_model_->GetIcon(); | |
| 280 } | |
| 281 | |
| 282 void OmniboxViewMac::SetUserText(const string16& text) { | |
| 283 SetUserText(text, text, true); | |
| 284 } | |
| 285 | |
| 286 void OmniboxViewMac::SetUserText(const string16& text, | |
| 287 const string16& display_text, | |
| 288 bool update_popup) { | |
| 289 model_->SetUserText(text); | |
| 290 // TODO(shess): TODO below from gtk. | |
| 291 // TODO(deanm): something about selection / focus change here. | |
| 292 SetWindowTextAndCaretPos(display_text, display_text.length(), update_popup, | |
| 293 true); | |
| 294 } | |
| 295 | |
| 296 NSRange OmniboxViewMac::GetSelectedRange() const { | 247 NSRange OmniboxViewMac::GetSelectedRange() const { |
| 297 return [[field_ currentEditor] selectedRange]; | 248 return [[field_ currentEditor] selectedRange]; |
| 298 } | 249 } |
| 299 | 250 |
| 300 NSRange OmniboxViewMac::GetMarkedRange() const { | 251 NSRange OmniboxViewMac::GetMarkedRange() const { |
| 301 DCHECK([field_ currentEditor]); | 252 DCHECK([field_ currentEditor]); |
| 302 return [(NSTextView*)[field_ currentEditor] markedRange]; | 253 return [(NSTextView*)[field_ currentEditor] markedRange]; |
| 303 } | 254 } |
| 304 | 255 |
| 305 void OmniboxViewMac::SetSelectedRange(const NSRange range) { | 256 void OmniboxViewMac::SetSelectedRange(const NSRange range) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 375 // TODO(shess): Figure out what |reversed| implies. The gtk version | 326 // TODO(shess): Figure out what |reversed| implies. The gtk version |
| 376 // has it imply inverting the selection front to back, but I don't | 327 // has it imply inverting the selection front to back, but I don't |
| 377 // even know if that makes sense for Mac. | 328 // even know if that makes sense for Mac. |
| 378 | 329 |
| 379 // TODO(shess): Verify that we should be stealing focus at this | 330 // TODO(shess): Verify that we should be stealing focus at this |
| 380 // point. | 331 // point. |
| 381 SetSelectedRange(NSMakeRange(0, GetTextLength())); | 332 SetSelectedRange(NSMakeRange(0, GetTextLength())); |
| 382 } | 333 } |
| 383 | 334 |
| 384 void OmniboxViewMac::RevertAll() { | 335 void OmniboxViewMac::RevertAll() { |
| 385 ClosePopup(); | 336 OmniboxView::RevertAll(); |
| 386 model_->Revert(); | |
| 387 model_->OnChanged(); | |
| 388 [field_ clearUndoChain]; | 337 [field_ clearUndoChain]; |
| 389 } | 338 } |
| 390 | 339 |
| 391 void OmniboxViewMac::UpdatePopup() { | 340 void OmniboxViewMac::UpdatePopup() { |
| 392 model_->SetInputInProgress(true); | 341 model_->SetInputInProgress(true); |
| 393 if (!model_->has_focus()) | 342 if (!model_->has_focus()) |
| 394 return; | 343 return; |
| 395 | 344 |
| 396 // Comment copied from OmniboxViewWin::UpdatePopup(): | 345 // Comment copied from OmniboxViewWin::UpdatePopup(): |
| 397 // Don't inline autocomplete when: | 346 // Don't inline autocomplete when: |
| 398 // * The user is deleting text | 347 // * The user is deleting text |
| 399 // * The caret/selection isn't at the end of the text | 348 // * The caret/selection isn't at the end of the text |
| 400 // * The user has just pasted in something that replaced all the text | 349 // * The user has just pasted in something that replaced all the text |
| 401 // * The user is trying to compose something in an IME | 350 // * The user is trying to compose something in an IME |
| 402 bool prevent_inline_autocomplete = IsImeComposing(); | 351 bool prevent_inline_autocomplete = IsImeComposing(); |
| 403 NSTextView* editor = (NSTextView*)[field_ currentEditor]; | 352 NSTextView* editor = (NSTextView*)[field_ currentEditor]; |
| 404 if (editor) { | 353 if (editor) { |
| 405 if (NSMaxRange([editor selectedRange]) < | 354 if (NSMaxRange([editor selectedRange]) < |
| 406 [[editor textStorage] length] - suggest_text_length_) | 355 [[editor textStorage] length] - suggest_text_length_) |
| 407 prevent_inline_autocomplete = true; | 356 prevent_inline_autocomplete = true; |
| 408 } | 357 } |
| 409 | 358 |
| 410 model_->StartAutocomplete([editor selectedRange].length != 0, | 359 model_->StartAutocomplete([editor selectedRange].length != 0, |
| 411 prevent_inline_autocomplete); | 360 prevent_inline_autocomplete); |
| 412 } | 361 } |
| 413 | 362 |
| 414 void OmniboxViewMac::ClosePopup() { | |
| 415 model_->StopAutocomplete(); | |
| 416 } | |
| 417 | |
| 418 void OmniboxViewMac::SetFocus() { | 363 void OmniboxViewMac::SetFocus() { |
| 419 } | 364 } |
| 420 | 365 |
| 421 void OmniboxViewMac::SetText(const string16& display_text) { | 366 void OmniboxViewMac::SetText(const string16& display_text) { |
| 422 // If we are setting the text directly, there cannot be any suggest text. | 367 // If we are setting the text directly, there cannot be any suggest text. |
| 423 suggest_text_length_ = 0; | 368 suggest_text_length_ = 0; |
| 424 SetTextInternal(display_text); | 369 SetTextInternal(display_text); |
| 425 } | 370 } |
| 426 | 371 |
| 427 void OmniboxViewMac::SetTextInternal(const string16& display_text) { | 372 void OmniboxViewMac::SetTextInternal(const string16& display_text) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 490 [storage setAttributes:[NSDictionary dictionary] | 435 [storage setAttributes:[NSDictionary dictionary] |
| 491 range:NSMakeRange(0, [storage length])]; | 436 range:NSMakeRange(0, [storage length])]; |
| 492 ApplyTextAttributes(GetText(), storage); | 437 ApplyTextAttributes(GetText(), storage); |
| 493 | 438 |
| 494 [storage endEditing]; | 439 [storage endEditing]; |
| 495 } else { | 440 } else { |
| 496 SetText(GetText()); | 441 SetText(GetText()); |
| 497 } | 442 } |
| 498 } | 443 } |
| 499 | 444 |
| 500 void OmniboxViewMac::TextChanged() { | |
| 501 EmphasizeURLComponents(); | |
| 502 model_->OnChanged(); | |
| 503 } | |
| 504 | |
| 505 void OmniboxViewMac::ApplyTextAttributes(const string16& display_text, | 445 void OmniboxViewMac::ApplyTextAttributes(const string16& display_text, |
| 506 NSMutableAttributedString* as) { | 446 NSMutableAttributedString* as) { |
| 507 NSUInteger as_length = [as length]; | 447 NSUInteger as_length = [as length]; |
| 508 NSRange as_entire_string = NSMakeRange(0, as_length); | 448 NSRange as_entire_string = NSMakeRange(0, as_length); |
| 509 | 449 |
| 510 [as addAttribute:NSFontAttributeName value:GetFieldFont() | 450 [as addAttribute:NSFontAttributeName value:GetFieldFont() |
| 511 range:as_entire_string]; | 451 range:as_entire_string]; |
| 512 | 452 |
| 513 // A kinda hacky way to add breaking at periods. This is what Safari does. | 453 // A kinda hacky way to add breaking at periods. This is what Safari does. |
| 514 // This works for IDNs too, despite the "en_US". | 454 // This works for IDNs too, despite the "en_US". |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 678 gfx::NativeView OmniboxViewMac::GetNativeView() const { | 618 gfx::NativeView OmniboxViewMac::GetNativeView() const { |
| 679 return field_; | 619 return field_; |
| 680 } | 620 } |
| 681 | 621 |
| 682 gfx::NativeView OmniboxViewMac::GetRelativeWindowForPopup() const { | 622 gfx::NativeView OmniboxViewMac::GetRelativeWindowForPopup() const { |
| 683 // Not used on mac. | 623 // Not used on mac. |
| 684 NOTREACHED(); | 624 NOTREACHED(); |
| 685 return NULL; | 625 return NULL; |
| 686 } | 626 } |
| 687 | 627 |
| 688 CommandUpdater* OmniboxViewMac::GetCommandUpdater() { | |
| 689 return command_updater_; | |
| 690 } | |
| 691 | |
| 692 void OmniboxViewMac::SetInstantSuggestion(const string16& suggest_text, | 628 void OmniboxViewMac::SetInstantSuggestion(const string16& suggest_text, |
| 693 bool animate_to_complete) { | 629 bool animate_to_complete) { |
| 694 NSString* text = GetNonSuggestTextSubstring(); | 630 NSString* text = GetNonSuggestTextSubstring(); |
| 695 bool needs_update = (suggest_text_length_ > 0); | 631 bool needs_update = (suggest_text_length_ > 0); |
| 696 | 632 |
| 697 // Append the new suggest text. | 633 // Append the new suggest text. |
| 698 suggest_text_length_ = suggest_text.length(); | 634 suggest_text_length_ = suggest_text.length(); |
| 699 if (suggest_text_length_ > 0) { | 635 if (suggest_text_length_ > 0) { |
| 700 text = [text stringByAppendingString:base::SysUTF16ToNSString( | 636 text = [text stringByAppendingString:base::SysUTF16ToNSString( |
| 701 suggest_text)]; | 637 suggest_text)]; |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 959 // should be really cheap, but in this case we could probably make | 895 // should be really cheap, but in this case we could probably make |
| 960 // things even cheaper by refactoring between the popup-placement | 896 // things even cheaper by refactoring between the popup-placement |
| 961 // code and the matrix-population code. | 897 // code and the matrix-population code. |
| 962 popup_view_->UpdatePopupAppearance(); | 898 popup_view_->UpdatePopupAppearance(); |
| 963 model_->PopupBoundsChangedTo(popup_view_->GetTargetBounds()); | 899 model_->PopupBoundsChangedTo(popup_view_->GetTargetBounds()); |
| 964 | 900 |
| 965 // Give controller a chance to rearrange decorations. | 901 // Give controller a chance to rearrange decorations. |
| 966 model_->OnChanged(); | 902 model_->OnChanged(); |
| 967 } | 903 } |
| 968 | 904 |
| 905 void OmniboxViewMac::ClosePopup() { | |
| 906 OmniboxView::ClosePopup(); | |
| 907 } | |
| 908 | |
| 969 bool OmniboxViewMac::OnBackspacePressed() { | 909 bool OmniboxViewMac::OnBackspacePressed() { |
| 970 // Don't intercept if not in keyword search mode. | 910 // Don't intercept if not in keyword search mode. |
| 971 if (model_->is_keyword_hint() || model_->keyword().empty()) { | 911 if (model_->is_keyword_hint() || model_->keyword().empty()) { |
| 972 return false; | 912 return false; |
| 973 } | 913 } |
| 974 | 914 |
| 975 // Don't intercept if there is a selection, or the cursor isn't at | 915 // Don't intercept if there is a selection, or the cursor isn't at |
| 976 // the leftmost position. | 916 // the leftmost position. |
| 977 const NSRange selection = GetSelectedRange(); | 917 const NSRange selection = GetSelectedRange(); |
| 978 if (selection.length > 0 || selection.location > 0) { | 918 if (selection.length > 0 || selection.location > 0) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1026 DCHECK_EQ([field_ currentEditor], [[field_ window] firstResponder]); | 966 DCHECK_EQ([field_ currentEditor], [[field_ window] firstResponder]); |
| 1027 } | 967 } |
| 1028 } | 968 } |
| 1029 | 969 |
| 1030 // static | 970 // static |
| 1031 NSFont* OmniboxViewMac::GetFieldFont() { | 971 NSFont* OmniboxViewMac::GetFieldFont() { |
| 1032 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 972 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 1033 return rb.GetFont(ResourceBundle::BaseFont).GetNativeFont(); | 973 return rb.GetFont(ResourceBundle::BaseFont).GetNativeFont(); |
| 1034 } | 974 } |
| 1035 | 975 |
| 976 int OmniboxViewMac::GetOmniboxTextLength() const { | |
| 977 return static_cast<int>(GetTextLength()); | |
|
Peter Kasting
2012/07/26 03:59:17
Nit: For all these derived classes, I kind of feel
dominich
2012/07/26 22:33:24
I originally built this however there are some pro
Peter Kasting
2012/07/26 23:03:24
My hope was that for most of those cases, if we we
| |
| 978 } | |
| 979 | |
| 1036 NSUInteger OmniboxViewMac::GetTextLength() const { | 980 NSUInteger OmniboxViewMac::GetTextLength() const { |
| 1037 return ([field_ currentEditor] ? | 981 return ([field_ currentEditor] ? |
| 1038 [[[field_ currentEditor] string] length] : | 982 [[[field_ currentEditor] string] length] : |
| 1039 [[field_ stringValue] length]) - suggest_text_length_; | 983 [[field_ stringValue] length]) - suggest_text_length_; |
| 1040 } | 984 } |
| 1041 | 985 |
| 1042 void OmniboxViewMac::PlaceCaretAt(NSUInteger pos) { | |
| 1043 DCHECK(pos <= GetTextLength()); | |
| 1044 SetSelectedRange(NSMakeRange(pos, pos)); | |
| 1045 } | |
| 1046 | |
| 1047 bool OmniboxViewMac::IsCaretAtEnd() const { | 986 bool OmniboxViewMac::IsCaretAtEnd() const { |
| 1048 const NSRange selection = GetSelectedRange(); | 987 const NSRange selection = GetSelectedRange(); |
| 1049 return selection.length == 0 && selection.location == GetTextLength(); | 988 return selection.length == 0 && |
| 989 selection.location == GetTextLength(); | |
| 1050 } | 990 } |
| OLD | NEW |