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

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

Issue 114017: Use Chrome facilities for omnibox state save and restore on Mac. (Closed)
Patch Set: Wordsmithing. Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/autocomplete/autocomplete_edit_view_mac.h ('k') | chrome/browser/browser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h" 5 #include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
6 6
7 #include "base/sys_string_conversions.h" 7 #include "base/sys_string_conversions.h"
8 #include "chrome/browser/autocomplete/autocomplete_edit.h" 8 #include "chrome/browser/autocomplete/autocomplete_edit.h"
9 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" 9 #include "chrome/browser/autocomplete/autocomplete_popup_model.h"
10 #include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h" 10 #include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h"
11 #include "chrome/browser/tab_contents/tab_contents.h"
12
13 namespace {
14
15 // Store's the model and view state across tab switches.
16 struct AutocompleteEditViewMacState {
17 AutocompleteEditViewMacState(const AutocompleteEditModel::State model_state,
18 const bool has_focus, const NSRange& selection)
19 : model_state(model_state),
20 has_focus(has_focus),
21 selection(selection) {
22 }
23
24 const AutocompleteEditModel::State model_state;
25 const bool has_focus;
26 const NSRange selection;
27 };
28
29 // Returns a lazily initialized property bag accessor for saving our
30 // state in a TabContents.
31 PropertyAccessor<AutocompleteEditViewMacState>* GetStateAccessor() {
32 static PropertyAccessor<AutocompleteEditViewMacState> state;
pink (ping after 24hrs) 2009/05/08 21:18:26 how does this work with multiple windows if there'
Scott Hess - ex-Googler 2009/05/08 22:50:21 Oh, I hope I don't hurt myself, here ... brief sum
pink (ping after 24hrs) 2009/05/11 13:50:11 I figured it was something like this. Maybe a comm
33 return &state;
34 }
35
36 // Accessors for storing and getting the state from the tab.
37 void StoreStateToTab(TabContents* tab,
38 const AutocompleteEditViewMacState& state) {
39 GetStateAccessor()->SetProperty(tab->property_bag(), state);
40 }
41 const AutocompleteEditViewMacState* GetStateFromTab(const TabContents* tab) {
42 return GetStateAccessor()->GetProperty(tab->property_bag());
43 }
44
45 } // namespace
11 46
12 // Thin Obj-C bridge class that is the delegate of the omnibox field. 47 // Thin Obj-C bridge class that is the delegate of the omnibox field.
13 // It intercepts various control delegate methods and vectors them to 48 // It intercepts various control delegate methods and vectors them to
14 // the edit view. 49 // the edit view.
15 50
16 @interface AutocompleteFieldDelegate : NSObject { 51 @interface AutocompleteFieldDelegate : NSObject {
17 @private 52 @private
18 AutocompleteEditViewMac* edit_view_; // weak, owns us. 53 AutocompleteEditViewMac* edit_view_; // weak, owns us.
19 } 54 }
20 - initWithEditView:(AutocompleteEditViewMac*)view; 55 - initWithEditView:(AutocompleteEditViewMac*)view;
(...skipping 29 matching lines...) Expand all
50 // back in the destructor. Likewise for destroying the model before 85 // back in the destructor. Likewise for destroying the model before
51 // this object. 86 // this object.
52 popup_view_.reset(); 87 popup_view_.reset();
53 model_.reset(); 88 model_.reset();
54 89
55 // Disconnect field_ from edit_helper_ so that we don't get calls 90 // Disconnect field_ from edit_helper_ so that we don't get calls
56 // after destruction. 91 // after destruction.
57 [field_ setDelegate:nil]; 92 [field_ setDelegate:nil];
58 } 93 }
59 94
60 // TODO(shess): This is the minimal change which seems to unblock
61 // getting the minimal Omnibox code checked in without making the
62 // world worse. Browser::TabSelectedAt() calls this when the tab
63 // changes, but that is only wired up for Windows. I do not yet
64 // understand that code well enough to go for it. Once wired up, then
65 // code can be removed at:
66 // [TabContentsController defocusLocationBar]
67 // [TabStripController selectTabWithContents:...]
68 void AutocompleteEditViewMac::SaveStateToTab(TabContents* tab) { 95 void AutocompleteEditViewMac::SaveStateToTab(TabContents* tab) {
69 // TODO(shess): Actually save the state to the tab area. 96 DCHECK(tab);
70 97
71 // Drop the popup before we change to another tab. 98 NSRange range;
72 ClosePopup(); 99 if (model_->has_focus()) {
100 range = GetSelectedRange();
101 } else {
102 // If we are not focussed, there is no selection. Manufacture
103 // something reasonable in case it starts to matter in the future.
104 range = NSMakeRange(0, [[field_ stringValue] length]);
105 }
106
107 AutocompleteEditViewMacState state(model_->GetStateForTabSwitch(),
108 model_->has_focus(), range);
109 StoreStateToTab(tab, state);
110 }
111
112 void AutocompleteEditViewMac::Update(
113 const TabContents* tab_for_state_restoring) {
114 // TODO(shess): It seems like if the tab is non-NULL, then this code
115 // shouldn't need to be called at all. When coded that way, I find
116 // that the field isn't always updated correctly. Figure out why
117 // this is. Maybe this method should be refactored into more
118 // specific cases.
119 const std::wstring text = toolbar_model_->GetText();
120 const bool user_visible = model_->UpdatePermanentText(text);
121
122 if (tab_for_state_restoring) {
123 RevertAll();
124
125 const AutocompleteEditViewMacState* state =
126 GetStateFromTab(tab_for_state_restoring);
127 if (state) {
128 // Should restore the user's text via SetUserText().
129 model_->RestoreState(state->model_state);
130
131 // Restore user's selection.
132 // TODO(shess): The model_ does not restore the focus state. If
133 // field_ was in focus when we switched away, I presume it
134 // should be in focus when we switch back. Figure out if model_
135 // not restoring focus is an oversight, or intentional for some
136 // subtle reason.
137 if (state->has_focus) {
138 FocusLocation();
139 DCHECK([field_ currentEditor]);
140 [[field_ currentEditor] setSelectedRange:state->selection];
141 }
142 }
143 } else if (user_visible) {
144 // Restore everything to the baseline look.
145 RevertAll();
146 // TODO(shess): Figure out how this case is used, to make sure
147 // we're getting the selection and popup right.
148
149 } else {
150 // TODO(shess): Figure out how this case is used, to make sure
151 // we're getting the selection and popup right.
152 // UpdateAndStyleText() approximates the inner part of Revertall()
153 // which under GTK is called EmphasizeURLComponents(), and is
154 // expected to change when I start feeding in the styling code.
155 UpdateAndStyleText(text, 0);
156 }
73 } 157 }
74 158
75 void AutocompleteEditViewMac::OpenURL(const GURL& url, 159 void AutocompleteEditViewMac::OpenURL(const GURL& url,
76 WindowOpenDisposition disposition, 160 WindowOpenDisposition disposition,
77 PageTransition::Type transition, 161 PageTransition::Type transition,
78 const GURL& alternate_nav_url, 162 const GURL& alternate_nav_url,
79 size_t selected_line, 163 size_t selected_line,
80 const std::wstring& keyword) { 164 const std::wstring& keyword) {
81 // TODO(shess): Why is the caller passing an invalid url in the 165 // TODO(shess): Why is the caller passing an invalid url in the
82 // first place? Make sure that case isn't being dropped on the 166 // first place? Make sure that case isn't being dropped on the
83 // floor. 167 // floor.
84 if (!url.is_valid()) { 168 if (!url.is_valid()) {
85 return; 169 return;
86 } 170 }
87 171
88 model_->SendOpenNotification(selected_line, keyword); 172 model_->SendOpenNotification(selected_line, keyword);
89 173
90 if (disposition != NEW_BACKGROUND_TAB) 174 if (disposition != NEW_BACKGROUND_TAB)
91 RevertAll(); // Revert the box to its unedited state. 175 RevertAll(); // Revert the box to its unedited state.
92 controller_->OnAutocompleteAccept(url, disposition, transition, 176 controller_->OnAutocompleteAccept(url, disposition, transition,
93 alternate_nav_url); 177 alternate_nav_url);
94 } 178 }
95 179
96 std::wstring AutocompleteEditViewMac::GetText() const { 180 std::wstring AutocompleteEditViewMac::GetText() const {
97 return base::SysNSStringToWide([field_ stringValue]); 181 return base::SysNSStringToWide([field_ stringValue]);
98 } 182 }
99 183
184 void AutocompleteEditViewMac::SetUserText(const std::wstring& text,
185 const std::wstring& display_text,
186 bool update_popup) {
187 model_->SetUserText(text);
188 UpdateAndStyleText(display_text, display_text.size());
189 if (update_popup) {
190 UpdatePopup();
191 }
192 }
193
100 NSRange AutocompleteEditViewMac::GetSelectedRange() const { 194 NSRange AutocompleteEditViewMac::GetSelectedRange() const {
101 DCHECK([field_ currentEditor]); 195 DCHECK([field_ currentEditor]);
102 return [[field_ currentEditor] selectedRange]; 196 return [[field_ currentEditor] selectedRange];
103 } 197 }
104 198
105 void AutocompleteEditViewMac::SetWindowTextAndCaretPos(const std::wstring& text, 199 void AutocompleteEditViewMac::SetWindowTextAndCaretPos(const std::wstring& text,
106 size_t caret_pos) { 200 size_t caret_pos) {
107 UpdateAndStyleText(text, text.size()); 201 UpdateAndStyleText(text, text.size());
108 } 202 }
109 203
110 void AutocompleteEditViewMac::SelectAll(bool reversed) { 204 void AutocompleteEditViewMac::SelectAll(bool reversed) {
111 // TODO(shess): Figure out what reversed implies. The gtk version 205 // TODO(shess): Figure out what reversed implies. The gtk version
112 // has it imply inverting the selection front to back, but I don't 206 // has it imply inverting the selection front to back, but I don't
113 // even know if that makes sense for Mac. 207 // even know if that makes sense for Mac.
114 UpdateAndStyleText(GetText(), 0); 208 UpdateAndStyleText(GetText(), 0);
115 } 209 }
116 210
117 void AutocompleteEditViewMac::RevertAll() { 211 void AutocompleteEditViewMac::RevertAll() {
118 ClosePopup(); 212 ClosePopup();
119 model_->Revert(); 213 model_->Revert();
120 214
121 std::wstring tt = GetText(); 215 std::wstring tt = GetText();
122 UpdateAndStyleText(tt, tt.size()); 216 UpdateAndStyleText(tt, 0);
123 controller_->OnChanged(); 217 controller_->OnChanged();
124 } 218 }
125 219
126 void AutocompleteEditViewMac::UpdatePopup() { 220 void AutocompleteEditViewMac::UpdatePopup() {
127 model_->SetInputInProgress(true); 221 model_->SetInputInProgress(true);
128 if (!model_->has_focus()) 222 if (!model_->has_focus())
129 return; 223 return;
130 224
131 // TODO(shess): 225 // TODO(shess):
132 // Shouldn't inline autocomplete when the caret/selection isn't at 226 // Shouldn't inline autocomplete when the caret/selection isn't at
(...skipping 16 matching lines...) Expand all
149 243
150 url_parse::Parsed parts; 244 url_parse::Parsed parts;
151 AutocompleteInput::Parse(display_text, model_->GetDesiredTLD(), 245 AutocompleteInput::Parse(display_text, model_->GetDesiredTLD(),
152 &parts, NULL); 246 &parts, NULL);
153 bool emphasize = model_->CurrentTextIsURL() && (parts.host.len > 0); 247 bool emphasize = model_->CurrentTextIsURL() && (parts.host.len > 0);
154 if (emphasize) { 248 if (emphasize) {
155 // TODO(shess): Pull color out as a constant. 249 // TODO(shess): Pull color out as a constant.
156 [as addAttribute:NSForegroundColorAttributeName 250 [as addAttribute:NSForegroundColorAttributeName
157 value:[NSColor greenColor] 251 value:[NSColor greenColor]
158 range:NSMakeRange((NSInteger)parts.host.begin, 252 range:NSMakeRange((NSInteger)parts.host.begin,
159 (NSInteger)parts.host.end())]; 253 (NSInteger)parts.host.len)];
160 } 254 }
161 255
162 // TODO(shess): GTK has this as a member var, figure out why. 256 // TODO(shess): GTK has this as a member var, figure out why.
163 ToolbarModel::SecurityLevel scheme_security_level = 257 ToolbarModel::SecurityLevel scheme_security_level =
164 toolbar_model_->GetSchemeSecurityLevel(); 258 toolbar_model_->GetSchemeSecurityLevel();
165 259
166 // Emphasize the scheme for security UI display purposes (if necessary). 260 // Emphasize the scheme for security UI display purposes (if necessary).
167 if (!model_->user_input_in_progress() && parts.scheme.is_nonempty() && 261 if (!model_->user_input_in_progress() && parts.scheme.is_nonempty() &&
168 (scheme_security_level != ToolbarModel::NORMAL)) { 262 (scheme_security_level != ToolbarModel::NORMAL)) {
169 // TODO(shess): Pull colors out as constants. 263 // TODO(shess): Pull colors out as constants.
170 NSColor* color; 264 NSColor* color;
171 if (scheme_security_level == ToolbarModel::SECURE) { 265 if (scheme_security_level == ToolbarModel::SECURE) {
172 color = [NSColor blueColor]; 266 color = [NSColor blueColor];
173 } else { 267 } else {
174 color = [NSColor blackColor]; 268 color = [NSColor blackColor];
175 } 269 }
176 [as addAttribute:NSForegroundColorAttributeName value:color 270 [as addAttribute:NSForegroundColorAttributeName value:color
177 range:NSMakeRange((NSInteger)parts.scheme.begin, 271 range:NSMakeRange((NSInteger)parts.scheme.begin,
178 (NSInteger)parts.scheme.end())]; 272 (NSInteger)parts.scheme.len)];
179 } 273 }
180 274
181 // TODO(shess): Check that this updates the model's sense of focus 275 // TODO(shess): Check that this updates the model's sense of focus
182 // correctly. 276 // correctly.
183 [field_ setObjectValue:as]; 277 [field_ setObjectValue:as];
184 if (![field_ currentEditor]) { 278 if (![field_ currentEditor]) {
185 [field_ becomeFirstResponder]; 279 [field_ becomeFirstResponder];
186 DCHECK_EQ(field_, [[field_ window] firstResponder]); 280 DCHECK_EQ([field_ currentEditor], [[field_ window] firstResponder]);
187 } 281 }
188 282
189 NSRange selected_range = NSMakeRange(user_text_length, [as length]); 283 NSRange selected_range = NSMakeRange(user_text_length, [as length]);
190 // TODO(shess): What if it didn't get first responder, and there is 284 // TODO(shess): What if it didn't get first responder, and there is
191 // no field editor? This will do nothing. Well, at least it won't 285 // no field editor? This will do nothing. Well, at least it won't
192 // crash. Think of something more productive to do, or prove that 286 // crash. Think of something more productive to do, or prove that
193 // it cannot occur and DCHECK appropriately. 287 // it cannot occur and DCHECK appropriately.
194 [[field_ currentEditor] setSelectedRange:selected_range]; 288 [[field_ currentEditor] setSelectedRange:selected_range];
195 } 289 }
196 290
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 } 368 }
275 void AutocompleteEditViewMac::OnKillFocus() { 369 void AutocompleteEditViewMac::OnKillFocus() {
276 model_->OnKillFocus(); 370 model_->OnKillFocus();
277 } 371 }
278 void AutocompleteEditViewMac::AcceptInput( 372 void AutocompleteEditViewMac::AcceptInput(
279 WindowOpenDisposition disposition, bool for_drop) { 373 WindowOpenDisposition disposition, bool for_drop) {
280 model_->AcceptInput(disposition, for_drop); 374 model_->AcceptInput(disposition, for_drop);
281 } 375 }
282 376
283 void AutocompleteEditViewMac::FocusLocation() { 377 void AutocompleteEditViewMac::FocusLocation() {
284 [[field_ window] makeFirstResponder:field_]; 378 // -makeFirstResponder: will select the entire field_. If we're
379 // already firstResponder, it's likely that we want to retain the
380 // current selection.
381 if (![field_ currentEditor]) {
382 [[field_ window] makeFirstResponder:field_];
383 }
285 } 384 }
286 385
287 @implementation AutocompleteFieldDelegate 386 @implementation AutocompleteFieldDelegate
288 387
289 - initWithEditView:(AutocompleteEditViewMac*)view { 388 - initWithEditView:(AutocompleteEditViewMac*)view {
290 self = [super init]; 389 self = [super init];
291 if (self) { 390 if (self) {
292 edit_view_ = view; 391 edit_view_ = view;
293 } 392 }
294 return self; 393 return self;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 } 448 }
350 449
351 - (void)controlTextDidEndEditing:(NSNotification*)aNotification { 450 - (void)controlTextDidEndEditing:(NSNotification*)aNotification {
352 edit_view_->OnKillFocus(); 451 edit_view_->OnKillFocus();
353 452
354 // TODO(shess): Figure out where the selection belongs. On GTK, 453 // TODO(shess): Figure out where the selection belongs. On GTK,
355 // it's set to the start of the text. 454 // it's set to the start of the text.
356 } 455 }
357 456
358 @end 457 @end
OLDNEW
« no previous file with comments | « chrome/browser/autocomplete/autocomplete_edit_view_mac.h ('k') | chrome/browser/browser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698