| OLD | NEW |
| 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 namespace { | 13 namespace { |
| 14 | 14 |
| 15 // 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 |
| 17 // the same values easily. |
| 18 const NSColor* ColorWithRGBBytes(int rr, int gg, int bb) { |
| 19 DCHECK_LE(rr, 255); |
| 20 DCHECK_LE(bb, 255); |
| 21 DCHECK_LE(gg, 255); |
| 22 return [NSColor colorWithCalibratedRed:static_cast<float>(rr)/255.0 |
| 23 green:static_cast<float>(gg)/255.0 |
| 24 blue:static_cast<float>(bb)/255.0 |
| 25 alpha:1.0]; |
| 26 } |
| 27 const NSColor* SecureBackgroundColor() { |
| 28 return ColorWithRGBBytes(255, 245, 195); // Yellow |
| 29 } |
| 30 const NSColor* NormalBackgroundColor() { |
| 31 return [NSColor controlBackgroundColor]; |
| 32 } |
| 33 const NSColor* InsecureBackgroundColor() { |
| 34 return [NSColor controlBackgroundColor]; |
| 35 } |
| 36 |
| 37 const NSColor* HostTextColor() { |
| 38 return [NSColor blackColor]; |
| 39 } |
| 40 const NSColor* BaseTextColor() { |
| 41 return [NSColor darkGrayColor]; |
| 42 } |
| 43 const NSColor* SecureSchemeColor() { |
| 44 return ColorWithRGBBytes(0x00, 0x96, 0x14); |
| 45 } |
| 46 const NSColor* InsecureSchemeColor() { |
| 47 return ColorWithRGBBytes(0xc8, 0x00, 0x00); |
| 48 } |
| 49 |
| 15 // Store's the model and view state across tab switches. | 50 // Store's the model and view state across tab switches. |
| 16 struct AutocompleteEditViewMacState { | 51 struct AutocompleteEditViewMacState { |
| 17 AutocompleteEditViewMacState(const AutocompleteEditModel::State model_state, | 52 AutocompleteEditViewMacState(const AutocompleteEditModel::State model_state, |
| 18 const bool has_focus, const NSRange& selection) | 53 const bool has_focus, const NSRange& selection) |
| 19 : model_state(model_state), | 54 : model_state(model_state), |
| 20 has_focus(has_focus), | 55 has_focus(has_focus), |
| 21 selection(selection) { | 56 selection(selection) { |
| 22 } | 57 } |
| 23 | 58 |
| 24 const AutocompleteEditModel::State model_state; | 59 const AutocompleteEditModel::State model_state; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 37 | 72 |
| 38 // Accessors for storing and getting the state from the tab. | 73 // Accessors for storing and getting the state from the tab. |
| 39 void StoreStateToTab(TabContents* tab, | 74 void StoreStateToTab(TabContents* tab, |
| 40 const AutocompleteEditViewMacState& state) { | 75 const AutocompleteEditViewMacState& state) { |
| 41 GetStateAccessor()->SetProperty(tab->property_bag(), state); | 76 GetStateAccessor()->SetProperty(tab->property_bag(), state); |
| 42 } | 77 } |
| 43 const AutocompleteEditViewMacState* GetStateFromTab(const TabContents* tab) { | 78 const AutocompleteEditViewMacState* GetStateFromTab(const TabContents* tab) { |
| 44 return GetStateAccessor()->GetProperty(tab->property_bag()); | 79 return GetStateAccessor()->GetProperty(tab->property_bag()); |
| 45 } | 80 } |
| 46 | 81 |
| 82 // Helper to make converting url_parse ranges to NSRange easier to |
| 83 // read. |
| 84 NSRange ComponentToNSRange(const url_parse::Component& component) { |
| 85 return NSMakeRange(static_cast<NSInteger>(component.begin), |
| 86 static_cast<NSInteger>(component.len)); |
| 87 } |
| 88 |
| 47 } // namespace | 89 } // namespace |
| 48 | 90 |
| 49 // Thin Obj-C bridge class that is the delegate of the omnibox field. | 91 // Thin Obj-C bridge class that is the delegate of the omnibox field. |
| 50 // It intercepts various control delegate methods and vectors them to | 92 // It intercepts various control delegate methods and vectors them to |
| 51 // the edit view. | 93 // the edit view. |
| 52 | 94 |
| 53 @interface AutocompleteFieldDelegate : NSObject { | 95 @interface AutocompleteFieldDelegate : NSObject { |
| 54 @private | 96 @private |
| 55 AutocompleteEditViewMac* edit_view_; // weak, owns us. | 97 AutocompleteEditViewMac* edit_view_; // weak, owns us. |
| 56 } | 98 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 70 toolbar_model_(toolbar_model), | 112 toolbar_model_(toolbar_model), |
| 71 command_updater_(command_updater), | 113 command_updater_(command_updater), |
| 72 field_(field), | 114 field_(field), |
| 73 edit_helper_([[AutocompleteFieldDelegate alloc] initWithEditView:this]) { | 115 edit_helper_([[AutocompleteFieldDelegate alloc] initWithEditView:this]) { |
| 74 DCHECK(controller); | 116 DCHECK(controller); |
| 75 DCHECK(toolbar_model); | 117 DCHECK(toolbar_model); |
| 76 DCHECK(profile); | 118 DCHECK(profile); |
| 77 DCHECK(command_updater); | 119 DCHECK(command_updater); |
| 78 DCHECK(field); | 120 DCHECK(field); |
| 79 [field_ setDelegate:edit_helper_]; | 121 [field_ setDelegate:edit_helper_]; |
| 122 |
| 123 // Needed so that editing doesn't lose the styling. |
| 124 [field_ setAllowsEditingTextAttributes:YES]; |
| 80 } | 125 } |
| 81 | 126 |
| 82 AutocompleteEditViewMac::~AutocompleteEditViewMac() { | 127 AutocompleteEditViewMac::~AutocompleteEditViewMac() { |
| 83 // TODO(shess): Having to be aware of destructor ordering in this | 128 // TODO(shess): Having to be aware of destructor ordering in this |
| 84 // way seems brittle. There must be a better way. | 129 // way seems brittle. There must be a better way. |
| 85 | 130 |
| 86 // Destroy popup view before this object in case it tries to call us | 131 // Destroy popup view before this object in case it tries to call us |
| 87 // back in the destructor. Likewise for destroying the model before | 132 // back in the destructor. Likewise for destroying the model before |
| 88 // this object. | 133 // this object. |
| 89 popup_view_.reset(); | 134 popup_view_.reset(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 // Should restore the user's text via SetUserText(). | 175 // Should restore the user's text via SetUserText(). |
| 131 model_->RestoreState(state->model_state); | 176 model_->RestoreState(state->model_state); |
| 132 | 177 |
| 133 // Restore user's selection. | 178 // Restore user's selection. |
| 134 // TODO(shess): The model_ does not restore the focus state. If | 179 // TODO(shess): The model_ does not restore the focus state. If |
| 135 // field_ was in focus when we switched away, I presume it | 180 // field_ was in focus when we switched away, I presume it |
| 136 // should be in focus when we switch back. Figure out if model_ | 181 // should be in focus when we switch back. Figure out if model_ |
| 137 // not restoring focus is an oversight, or intentional for some | 182 // not restoring focus is an oversight, or intentional for some |
| 138 // subtle reason. | 183 // subtle reason. |
| 139 if (state->has_focus) { | 184 if (state->has_focus) { |
| 140 FocusLocation(); | 185 SetSelectedRange(state->selection); |
| 141 DCHECK([field_ currentEditor]); | |
| 142 [[field_ currentEditor] setSelectedRange:state->selection]; | |
| 143 } | 186 } |
| 144 } | 187 } |
| 145 } else if (user_visible) { | 188 } else if (user_visible) { |
| 146 // Restore everything to the baseline look. | 189 // Restore everything to the baseline look. |
| 147 RevertAll(); | 190 RevertAll(); |
| 148 // TODO(shess): Figure out how this case is used, to make sure | 191 // TODO(shess): Figure out how this case is used, to make sure |
| 149 // we're getting the selection and popup right. | 192 // we're getting the selection and popup right. |
| 150 | 193 |
| 151 } else { | 194 } else { |
| 152 // TODO(shess): Figure out how this case is used, to make sure | 195 // TODO(shess): Figure out how this case is used, to make sure |
| 153 // we're getting the selection and popup right. | 196 // we're getting the selection and popup right. |
| 154 // UpdateAndStyleText() approximates the inner part of Revertall() | 197 UpdateAndStyleText(text); |
| 155 // which under GTK is called EmphasizeURLComponents(), and is | |
| 156 // expected to change when I start feeding in the styling code. | |
| 157 UpdateAndStyleText(text, 0); | |
| 158 } | 198 } |
| 159 } | 199 } |
| 160 | 200 |
| 161 void AutocompleteEditViewMac::OpenURL(const GURL& url, | 201 void AutocompleteEditViewMac::OpenURL(const GURL& url, |
| 162 WindowOpenDisposition disposition, | 202 WindowOpenDisposition disposition, |
| 163 PageTransition::Type transition, | 203 PageTransition::Type transition, |
| 164 const GURL& alternate_nav_url, | 204 const GURL& alternate_nav_url, |
| 165 size_t selected_line, | 205 size_t selected_line, |
| 166 const std::wstring& keyword) { | 206 const std::wstring& keyword) { |
| 167 // TODO(shess): Why is the caller passing an invalid url in the | 207 // TODO(shess): Why is the caller passing an invalid url in the |
| (...skipping 12 matching lines...) Expand all Loading... |
| 180 } | 220 } |
| 181 | 221 |
| 182 std::wstring AutocompleteEditViewMac::GetText() const { | 222 std::wstring AutocompleteEditViewMac::GetText() const { |
| 183 return base::SysNSStringToWide([field_ stringValue]); | 223 return base::SysNSStringToWide([field_ stringValue]); |
| 184 } | 224 } |
| 185 | 225 |
| 186 void AutocompleteEditViewMac::SetUserText(const std::wstring& text, | 226 void AutocompleteEditViewMac::SetUserText(const std::wstring& text, |
| 187 const std::wstring& display_text, | 227 const std::wstring& display_text, |
| 188 bool update_popup) { | 228 bool update_popup) { |
| 189 model_->SetUserText(text); | 229 model_->SetUserText(text); |
| 190 UpdateAndStyleText(display_text, display_text.size()); | 230 // TODO(shess): TODO below from gtk. |
| 231 // TODO(deanm): something about selection / focus change here. |
| 232 UpdateAndStyleText(display_text); |
| 191 if (update_popup) { | 233 if (update_popup) { |
| 192 UpdatePopup(); | 234 UpdatePopup(); |
| 193 } | 235 } |
| 194 } | 236 } |
| 195 | 237 |
| 196 NSRange AutocompleteEditViewMac::GetSelectedRange() const { | 238 NSRange AutocompleteEditViewMac::GetSelectedRange() const { |
| 197 DCHECK([field_ currentEditor]); | 239 DCHECK([field_ currentEditor]); |
| 198 return [[field_ currentEditor] selectedRange]; | 240 return [[field_ currentEditor] selectedRange]; |
| 199 } | 241 } |
| 200 | 242 |
| 243 void AutocompleteEditViewMac::SetSelectedRange(const NSRange range) { |
| 244 // TODO(shess): Check if we should steal focus or not. We can't set |
| 245 // the selection without focus, though. |
| 246 FocusLocation(); |
| 247 |
| 248 // TODO(shess): What if it didn't get first responder, and there is |
| 249 // no field editor? This will do nothing. Well, at least it won't |
| 250 // crash. Think of something more productive to do, or prove that |
| 251 // it cannot occur and DCHECK appropriately. |
| 252 [[field_ currentEditor] setSelectedRange:range]; |
| 253 } |
| 254 |
| 201 void AutocompleteEditViewMac::SetWindowTextAndCaretPos(const std::wstring& text, | 255 void AutocompleteEditViewMac::SetWindowTextAndCaretPos(const std::wstring& text, |
| 202 size_t caret_pos) { | 256 size_t caret_pos) { |
| 203 UpdateAndStyleText(text, text.size()); | 257 DCHECK_LE(caret_pos, text.size()); |
| 258 UpdateAndStyleText(text); |
| 259 SetSelectedRange(NSMakeRange(caret_pos, caret_pos)); |
| 204 } | 260 } |
| 205 | 261 |
| 206 void AutocompleteEditViewMac::SelectAll(bool reversed) { | 262 void AutocompleteEditViewMac::SelectAll(bool reversed) { |
| 207 // TODO(shess): Figure out what reversed implies. The gtk version | 263 // TODO(shess): Figure out what |reversed| implies. The gtk version |
| 208 // has it imply inverting the selection front to back, but I don't | 264 // has it imply inverting the selection front to back, but I don't |
| 209 // even know if that makes sense for Mac. | 265 // even know if that makes sense for Mac. |
| 210 UpdateAndStyleText(GetText(), 0); | 266 |
| 267 // TODO(shess): Verify that we should be stealing focus at this |
| 268 // point. |
| 269 SetSelectedRange(NSMakeRange(0, GetText().size())); |
| 211 } | 270 } |
| 212 | 271 |
| 213 void AutocompleteEditViewMac::RevertAll() { | 272 void AutocompleteEditViewMac::RevertAll() { |
| 214 ClosePopup(); | 273 ClosePopup(); |
| 215 model_->Revert(); | 274 model_->Revert(); |
| 216 | 275 |
| 217 std::wstring tt = GetText(); | 276 UpdateAndStyleText(GetText()); |
| 218 UpdateAndStyleText(tt, 0); | |
| 219 controller_->OnChanged(); | 277 controller_->OnChanged(); |
| 220 } | 278 } |
| 221 | 279 |
| 222 void AutocompleteEditViewMac::UpdatePopup() { | 280 void AutocompleteEditViewMac::UpdatePopup() { |
| 223 model_->SetInputInProgress(true); | 281 model_->SetInputInProgress(true); |
| 224 if (!model_->has_focus()) | 282 if (!model_->has_focus()) |
| 225 return; | 283 return; |
| 226 | 284 |
| 227 // TODO(shess): | 285 // TODO(shess): |
| 228 // Shouldn't inline autocomplete when the caret/selection isn't at | 286 // Shouldn't inline autocomplete when the caret/selection isn't at |
| 229 // the end of the text. | 287 // the end of the text. |
| 230 // | 288 // |
| 231 // One option would seem to be to check for a non-nil field | 289 // One option would seem to be to check for a non-nil field |
| 232 // editor, and check it's selected range against its length. | 290 // editor, and check it's selected range against its length. |
| 233 model_->StartAutocomplete(false); | 291 model_->StartAutocomplete(false); |
| 234 } | 292 } |
| 235 | 293 |
| 236 void AutocompleteEditViewMac::ClosePopup() { | 294 void AutocompleteEditViewMac::ClosePopup() { |
| 237 popup_view_->GetModel()->StopAutocomplete(); | 295 popup_view_->GetModel()->StopAutocomplete(); |
| 238 } | 296 } |
| 239 | 297 |
| 240 void AutocompleteEditViewMac::UpdateAndStyleText( | 298 void AutocompleteEditViewMac::UpdateAndStyleText( |
| 241 const std::wstring& display_text, size_t user_text_length) { | 299 const std::wstring& display_text) { |
| 242 NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys: | |
| 243 [field_ font], NSFontAttributeName, | |
| 244 nil]; | |
| 245 NSString* ss = base::SysWideToNSString(display_text); | 300 NSString* ss = base::SysWideToNSString(display_text); |
| 246 NSMutableAttributedString* as = | 301 NSMutableAttributedString* as = |
| 247 [[[NSMutableAttributedString alloc] initWithString:ss | 302 [[[NSMutableAttributedString alloc] initWithString:ss] autorelease]; |
| 248 attributes:attributes] | 303 [as addAttribute:NSFontAttributeName value:[field_ font] |
| 249 autorelease]; | 304 range:NSMakeRange(0, [as length])]; |
| 250 | 305 |
| 251 url_parse::Parsed parts; | 306 url_parse::Parsed parts; |
| 252 AutocompleteInput::Parse(display_text, model_->GetDesiredTLD(), | 307 AutocompleteInput::Parse(display_text, model_->GetDesiredTLD(), |
| 253 &parts, NULL); | 308 &parts, NULL); |
| 254 bool emphasize = model_->CurrentTextIsURL() && (parts.host.len > 0); | 309 const bool emphasize = model_->CurrentTextIsURL() && (parts.host.len > 0); |
| 255 if (emphasize) { | 310 if (emphasize) { |
| 256 // TODO(shess): Pull color out as a constant. | 311 [as addAttribute:NSForegroundColorAttributeName value:BaseTextColor() |
| 257 [as addAttribute:NSForegroundColorAttributeName | 312 range:NSMakeRange(0, [as length])]; |
| 258 value:[NSColor greenColor] | 313 |
| 259 range:NSMakeRange((NSInteger)parts.host.begin, | 314 [as addAttribute:NSForegroundColorAttributeName value:HostTextColor() |
| 260 (NSInteger)parts.host.len)]; | 315 range:ComponentToNSRange(parts.host)]; |
| 261 } | 316 } |
| 262 | 317 |
| 263 // TODO(shess): GTK has this as a member var, figure out why. | 318 // TODO(shess): GTK has this as a member var, figure out why. |
| 264 ToolbarModel::SecurityLevel scheme_security_level = | 319 // [Could it be to not change if no change? If so, I'm guessing |
| 320 // AppKit may already handle that.] |
| 321 const ToolbarModel::SecurityLevel scheme_security_level = |
| 265 toolbar_model_->GetSchemeSecurityLevel(); | 322 toolbar_model_->GetSchemeSecurityLevel(); |
| 266 | 323 |
| 324 if (scheme_security_level == ToolbarModel::SECURE) { |
| 325 [field_ setBackgroundColor:SecureBackgroundColor()]; |
| 326 } else if (scheme_security_level == ToolbarModel::NORMAL) { |
| 327 [field_ setBackgroundColor:NormalBackgroundColor()]; |
| 328 } else if (scheme_security_level == ToolbarModel::INSECURE) { |
| 329 [field_ setBackgroundColor:InsecureBackgroundColor()]; |
| 330 } else { |
| 331 NOTREACHED() << "Unexpected scheme_security_level: " |
| 332 << scheme_security_level; |
| 333 } |
| 334 |
| 267 // Emphasize the scheme for security UI display purposes (if necessary). | 335 // Emphasize the scheme for security UI display purposes (if necessary). |
| 268 if (!model_->user_input_in_progress() && parts.scheme.is_nonempty() && | 336 if (!model_->user_input_in_progress() && parts.scheme.is_nonempty() && |
| 269 (scheme_security_level != ToolbarModel::NORMAL)) { | 337 (scheme_security_level != ToolbarModel::NORMAL)) { |
| 270 // TODO(shess): Pull colors out as constants. | |
| 271 NSColor* color; | 338 NSColor* color; |
| 272 if (scheme_security_level == ToolbarModel::SECURE) { | 339 if (scheme_security_level == ToolbarModel::SECURE) { |
| 273 color = [NSColor blueColor]; | 340 color = SecureSchemeColor(); |
| 274 } else { | 341 } else { |
| 275 color = [NSColor blackColor]; | 342 color = InsecureSchemeColor(); |
| 276 } | 343 } |
| 277 [as addAttribute:NSForegroundColorAttributeName value:color | 344 [as addAttribute:NSForegroundColorAttributeName value:color |
| 278 range:NSMakeRange((NSInteger)parts.scheme.begin, | 345 range:ComponentToNSRange(parts.scheme)]; |
| 279 (NSInteger)parts.scheme.len)]; | |
| 280 } | 346 } |
| 281 | 347 |
| 282 // TODO(shess): Check that this updates the model's sense of focus | |
| 283 // correctly. | |
| 284 [field_ setObjectValue:as]; | 348 [field_ setObjectValue:as]; |
| 285 if (![field_ currentEditor]) { | |
| 286 [field_ becomeFirstResponder]; | |
| 287 DCHECK_EQ([field_ currentEditor], [[field_ window] firstResponder]); | |
| 288 } | |
| 289 | |
| 290 NSRange selected_range = NSMakeRange(user_text_length, [as length]); | |
| 291 // TODO(shess): What if it didn't get first responder, and there is | |
| 292 // no field editor? This will do nothing. Well, at least it won't | |
| 293 // crash. Think of something more productive to do, or prove that | |
| 294 // it cannot occur and DCHECK appropriately. | |
| 295 [[field_ currentEditor] setSelectedRange:selected_range]; | |
| 296 } | 349 } |
| 297 | 350 |
| 298 void AutocompleteEditViewMac::OnTemporaryTextMaybeChanged( | 351 void AutocompleteEditViewMac::OnTemporaryTextMaybeChanged( |
| 299 const std::wstring& display_text, bool save_original_selection) { | 352 const std::wstring& display_text, bool save_original_selection) { |
| 300 // TODO(shess): I believe this is for when the user arrows around | 353 // TODO(shess): I believe this is for when the user arrows around |
| 301 // the popup, will be restored if they hit escape. Figure out if | 354 // the popup, will be restored if they hit escape. Figure out if |
| 302 // that is for certain it. | 355 // that is for certain it. |
| 303 if (save_original_selection) { | 356 if (save_original_selection) { |
| 357 saved_temporary_selection_ = GetSelectedRange(); |
| 304 saved_temporary_text_ = GetText(); | 358 saved_temporary_text_ = GetText(); |
| 305 } | 359 } |
| 306 | 360 |
| 307 UpdateAndStyleText(display_text, display_text.size()); | 361 SetWindowTextAndCaretPos(display_text, display_text.size()); |
| 308 } | 362 } |
| 309 | 363 |
| 310 bool AutocompleteEditViewMac::OnInlineAutocompleteTextMaybeChanged( | 364 bool AutocompleteEditViewMac::OnInlineAutocompleteTextMaybeChanged( |
| 311 const std::wstring& display_text, size_t user_text_length) { | 365 const std::wstring& display_text, size_t user_text_length) { |
| 312 // TODO(shess): Make sure that this actually works. The round trip | 366 // TODO(shess): Make sure that this actually works. The round trip |
| 313 // to native form and back may mean that it's the same but not the | 367 // to native form and back may mean that it's the same but not the |
| 314 // same. | 368 // same. |
| 315 if (display_text == GetText()) { | 369 if (display_text == GetText()) { |
| 316 return false; | 370 return false; |
| 317 } | 371 } |
| 318 | 372 |
| 319 UpdateAndStyleText(display_text, user_text_length); | 373 UpdateAndStyleText(display_text); |
| 374 DCHECK_LE(user_text_length, display_text.size()); |
| 375 SetSelectedRange(NSMakeRange(user_text_length, display_text.size())); |
| 320 return true; | 376 return true; |
| 321 } | 377 } |
| 322 | 378 |
| 323 void AutocompleteEditViewMac::OnRevertTemporaryText() { | 379 void AutocompleteEditViewMac::OnRevertTemporaryText() { |
| 324 UpdateAndStyleText(saved_temporary_text_, saved_temporary_text_.size()); | 380 UpdateAndStyleText(saved_temporary_text_); |
| 325 saved_temporary_text_.clear(); | 381 saved_temporary_text_.clear(); |
| 382 SetSelectedRange(saved_temporary_selection_); |
| 326 } | 383 } |
| 327 | 384 |
| 328 void AutocompleteEditViewMac::OnBeforePossibleChange() { | 385 void AutocompleteEditViewMac::OnBeforePossibleChange() { |
| 329 selection_before_change_ = GetSelectedRange(); | 386 selection_before_change_ = GetSelectedRange(); |
| 330 text_before_change_ = GetText(); | 387 text_before_change_ = GetText(); |
| 331 } | 388 } |
| 332 | 389 |
| 333 bool AutocompleteEditViewMac::OnAfterPossibleChange() { | 390 bool AutocompleteEditViewMac::OnAfterPossibleChange() { |
| 334 NSRange new_selection(GetSelectedRange()); | 391 const NSRange new_selection(GetSelectedRange()); |
| 335 std::wstring new_text(GetText()); | 392 const std::wstring new_text(GetText()); |
| 336 const size_t length = new_text.length(); | 393 const size_t length = new_text.length(); |
| 337 | 394 |
| 338 bool selection_differs = !NSEqualRanges(new_selection, | 395 const bool selection_differs = !NSEqualRanges(new_selection, |
| 339 selection_before_change_); | 396 selection_before_change_); |
| 340 bool at_end_of_edit = (length == new_selection.location); | 397 const bool at_end_of_edit = (length == new_selection.location); |
| 341 bool text_differs = (new_text != text_before_change_); | 398 const bool text_differs = (new_text != text_before_change_); |
| 342 | 399 |
| 343 // When the user has deleted text, we don't allow inline | 400 // When the user has deleted text, we don't allow inline |
| 344 // autocomplete. This is assumed if the text has gotten shorter AND | 401 // autocomplete. This is assumed if the text has gotten shorter AND |
| 345 // the selection has shifted towards the front of the text. During | 402 // the selection has shifted towards the front of the text. During |
| 346 // normal typing the text will almost always be shorter (as the new | 403 // normal typing the text will almost always be shorter (as the new |
| 347 // input replaces the autocomplete suggestion), but in that case the | 404 // input replaces the autocomplete suggestion), but in that case the |
| 348 // selection point will have moved towards the end of the text. | 405 // selection point will have moved towards the end of the text. |
| 349 // TODO(shess): In our implementation, we can catch -deleteBackward: | 406 // TODO(shess): In our implementation, we can catch -deleteBackward: |
| 350 // and other methods to provide positive knowledge that a delete | 407 // and other methods to provide positive knowledge that a delete |
| 351 // occured, rather than intuiting it from context. Consider whether | 408 // occured, rather than intuiting it from context. Consider whether |
| 352 // that would be a stronger approach. | 409 // that would be a stronger approach. |
| 353 bool just_deleted_text = | 410 const bool just_deleted_text = |
| 354 (length < text_before_change_.length() && | 411 (length < text_before_change_.length() && |
| 355 new_selection.location <= selection_before_change_.location); | 412 new_selection.location <= selection_before_change_.location); |
| 356 | 413 |
| 357 bool something_changed = model_->OnAfterPossibleChange(new_text, | 414 const bool something_changed = model_->OnAfterPossibleChange(new_text, |
| 358 selection_differs, text_differs, just_deleted_text, at_end_of_edit); | 415 selection_differs, text_differs, just_deleted_text, at_end_of_edit); |
| 359 | 416 |
| 360 // TODO(shess): Restyle the text if something_changed. Not fixing | 417 // Restyle if the user changed something. |
| 361 // now because styling is currently broken. | 418 // TODO(shess): Does this need to diver deeper to avoid flashing? |
| 419 // For instance, if the user types "/" after the hostname, will it |
| 420 // show as HostTextColor() for an instant before being replaced by |
| 421 // BaseTextColor(). This could probably be done by subclassing the |
| 422 // cell and intercepting draw requests so that we draw the right |
| 423 // thing every time. |
| 424 // NOTE(shess): That kind of thing would also help with when the |
| 425 // flashing from when the user's typing replaces the selection which |
| 426 // is then re-created with the new autocomplete results. |
| 427 if (something_changed) { |
| 428 UpdateAndStyleText(new_text); |
| 429 SetSelectedRange(new_selection); |
| 430 } |
| 362 | 431 |
| 363 return something_changed; | 432 return something_changed; |
| 364 } | 433 } |
| 365 | 434 |
| 366 void AutocompleteEditViewMac::OnUpOrDownKeyPressed(bool up, bool by_page) { | 435 void AutocompleteEditViewMac::OnUpOrDownKeyPressed(bool up, bool by_page) { |
| 367 int count = by_page ? model_->result().size() : 1; | 436 const int count = by_page ? model_->result().size() : 1; |
| 368 model_->OnUpOrDownKeyPressed(up ? -count : count); | 437 model_->OnUpOrDownKeyPressed(up ? -count : count); |
| 369 } | 438 } |
| 370 void AutocompleteEditViewMac::OnEscapeKeyPressed() { | 439 void AutocompleteEditViewMac::OnEscapeKeyPressed() { |
| 371 model_->OnEscapeKeyPressed(); | 440 model_->OnEscapeKeyPressed(); |
| 372 } | 441 } |
| 373 void AutocompleteEditViewMac::OnSetFocus(bool f) { | 442 void AutocompleteEditViewMac::OnSetFocus(bool f) { |
| 374 model_->OnSetFocus(f); | 443 model_->OnSetFocus(f); |
| 375 } | 444 } |
| 376 void AutocompleteEditViewMac::OnKillFocus() { | 445 void AutocompleteEditViewMac::OnKillFocus() { |
| 377 model_->OnKillFocus(); | 446 model_->OnKillFocus(); |
| 378 } | 447 } |
| 379 void AutocompleteEditViewMac::AcceptInput( | 448 void AutocompleteEditViewMac::AcceptInput( |
| 380 WindowOpenDisposition disposition, bool for_drop) { | 449 WindowOpenDisposition disposition, bool for_drop) { |
| 381 model_->AcceptInput(disposition, for_drop); | 450 model_->AcceptInput(disposition, for_drop); |
| 382 } | 451 } |
| 383 | 452 |
| 384 void AutocompleteEditViewMac::FocusLocation() { | 453 void AutocompleteEditViewMac::FocusLocation() { |
| 385 // -makeFirstResponder: will select the entire field_. If we're | 454 // -makeFirstResponder: will select the entire field_. If we're |
| 386 // already firstResponder, it's likely that we want to retain the | 455 // already firstResponder, it's likely that we want to retain the |
| 387 // current selection. | 456 // current selection. |
| 388 if (![field_ currentEditor]) { | 457 if (![field_ currentEditor]) { |
| 389 [[field_ window] makeFirstResponder:field_]; | 458 [[field_ window] makeFirstResponder:field_]; |
| 459 DCHECK_EQ([field_ currentEditor], [[field_ window] firstResponder]); |
| 390 } | 460 } |
| 391 } | 461 } |
| 392 | 462 |
| 393 @implementation AutocompleteFieldDelegate | 463 @implementation AutocompleteFieldDelegate |
| 394 | 464 |
| 395 - initWithEditView:(AutocompleteEditViewMac*)view { | 465 - initWithEditView:(AutocompleteEditViewMac*)view { |
| 396 self = [super init]; | 466 self = [super init]; |
| 397 if (self) { | 467 if (self) { |
| 398 edit_view_ = view; | 468 edit_view_ = view; |
| 399 } | 469 } |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 } | 525 } |
| 456 | 526 |
| 457 - (void)controlTextDidEndEditing:(NSNotification*)aNotification { | 527 - (void)controlTextDidEndEditing:(NSNotification*)aNotification { |
| 458 edit_view_->OnKillFocus(); | 528 edit_view_->OnKillFocus(); |
| 459 | 529 |
| 460 // TODO(shess): Figure out where the selection belongs. On GTK, | 530 // TODO(shess): Figure out where the selection belongs. On GTK, |
| 461 // it's set to the start of the text. | 531 // it's set to the start of the text. |
| 462 } | 532 } |
| 463 | 533 |
| 464 @end | 534 @end |
| OLD | NEW |