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

Side by Side Diff: chrome/browser/autocomplete/autocomplete_popup_model.cc

Issue 6340012: Fix a DCHECK failure in AutocompleteEditModel::OnPopupDataChanged() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update. Created 9 years, 11 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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_popup_model.h" 5 #include "chrome/browser/autocomplete/autocomplete_popup_model.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "unicode/ubidi.h" 9 #include "unicode/ubidi.h"
10 10
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 if ((hovered_line_ != kNoMatch) && (hovered_line_ != selected_line_)) 83 if ((hovered_line_ != kNoMatch) && (hovered_line_ != selected_line_))
84 view_->InvalidateLine(hovered_line_); 84 view_->InvalidateLine(hovered_line_);
85 85
86 // Change the hover to the new line. 86 // Change the hover to the new line.
87 hovered_line_ = line; 87 hovered_line_ = line;
88 if (!is_disabling && (hovered_line_ != selected_line_)) 88 if (!is_disabling && (hovered_line_ != selected_line_))
89 view_->InvalidateLine(hovered_line_); 89 view_->InvalidateLine(hovered_line_);
90 } 90 }
91 91
92 void AutocompletePopupModel::SetSelectedLine(size_t line, 92 void AutocompletePopupModel::SetSelectedLine(size_t line,
93 bool reset_to_default) { 93 bool reset_to_default,
94 bool force) {
94 // We should at least be dealing with the results of the current query. Note 95 // We should at least be dealing with the results of the current query. Note
95 // that even if |line| was valid on entry, this may make it invalid. We clamp 96 // that even if |line| was valid on entry, this may make it invalid. We clamp
96 // it below. 97 // it below.
97 controller_->CommitIfQueryHasNeverBeenCommitted(); 98 controller_->CommitIfQueryHasNeverBeenCommitted();
98 99
99 const AutocompleteResult& result = controller_->result(); 100 const AutocompleteResult& result = controller_->result();
100 if (result.empty()) 101 if (result.empty())
101 return; 102 return;
102 103
103 // Cancel the query so the matches don't change on the user. 104 // Cancel the query so the matches don't change on the user.
104 controller_->Stop(false); 105 controller_->Stop(false);
105 106
106 line = std::min(line, result.size() - 1); 107 line = std::min(line, result.size() - 1);
107 const AutocompleteMatch& match = result.match_at(line); 108 const AutocompleteMatch& match = result.match_at(line);
108 if (reset_to_default) { 109 if (reset_to_default) {
109 manually_selected_match_.Clear(); 110 manually_selected_match_.Clear();
110 } else { 111 } else {
111 // Track the user's selection until they cancel it. 112 // Track the user's selection until they cancel it.
112 manually_selected_match_.destination_url = match.destination_url; 113 manually_selected_match_.destination_url = match.destination_url;
113 manually_selected_match_.provider_affinity = match.provider; 114 manually_selected_match_.provider_affinity = match.provider;
114 manually_selected_match_.is_history_what_you_typed_match = 115 manually_selected_match_.is_history_what_you_typed_match =
115 match.is_history_what_you_typed_match; 116 match.is_history_what_you_typed_match;
116 } 117 }
117 118
118 if (line == selected_line_) 119 if (line == selected_line_ && !force)
119 return; // Nothing else to do. 120 return; // Nothing else to do.
120 121
121 // We need to update |selected_line_| before calling OnPopupDataChanged(), so 122 // We need to update |selected_line_| before calling OnPopupDataChanged(), so
122 // that when the edit notifies its controller that something has changed, the 123 // that when the edit notifies its controller that something has changed, the
123 // controller can get the correct updated data. 124 // controller can get the correct updated data.
124 // 125 //
125 // NOTE: We should never reach here with no selected line; the same code that 126 // NOTE: We should never reach here with no selected line; the same code that
126 // opened the popup and made it possible to get here should have also set a 127 // opened the popup and made it possible to get here should have also set a
127 // selected line. 128 // selected line.
128 CHECK(selected_line_ != kNoMatch); 129 CHECK(selected_line_ != kNoMatch);
(...skipping 22 matching lines...) Expand all
151 } 152 }
152 153
153 // Repaint old and new selected lines immediately, so that the edit doesn't 154 // Repaint old and new selected lines immediately, so that the edit doesn't
154 // appear to update [much] faster than the popup. 155 // appear to update [much] faster than the popup.
155 view_->PaintUpdatesNow(); 156 view_->PaintUpdatesNow();
156 } 157 }
157 158
158 void AutocompletePopupModel::ResetToDefaultMatch() { 159 void AutocompletePopupModel::ResetToDefaultMatch() {
159 const AutocompleteResult& result = controller_->result(); 160 const AutocompleteResult& result = controller_->result();
160 CHECK(!result.empty()); 161 CHECK(!result.empty());
161 SetSelectedLine(result.default_match() - result.begin(), true); 162 SetSelectedLine(result.default_match() - result.begin(), true, false);
162 view_->OnDragCanceled(); 163 view_->OnDragCanceled();
163 } 164 }
164 165
165 void AutocompletePopupModel::InfoForCurrentSelection( 166 void AutocompletePopupModel::InfoForCurrentSelection(
166 AutocompleteMatch* match, 167 AutocompleteMatch* match,
167 GURL* alternate_nav_url) const { 168 GURL* alternate_nav_url) const {
168 DCHECK(match != NULL); 169 DCHECK(match != NULL);
169 const AutocompleteResult* result; 170 const AutocompleteResult* result;
170 if (!controller_->done()) { 171 if (!controller_->done()) {
171 // NOTE: Using latest_result() is important here since not only could it 172 // NOTE: Using latest_result() is important here since not only could it
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 if (result.empty()) 261 if (result.empty())
261 return; 262 return;
262 263
263 // The user is using the keyboard to change the selection, so stop tracking 264 // The user is using the keyboard to change the selection, so stop tracking
264 // hover. 265 // hover.
265 SetHoveredLine(kNoMatch); 266 SetHoveredLine(kNoMatch);
266 267
267 // Clamp the new line to [0, result_.count() - 1]. 268 // Clamp the new line to [0, result_.count() - 1].
268 const size_t new_line = selected_line_ + count; 269 const size_t new_line = selected_line_ + count;
269 SetSelectedLine(((count < 0) && (new_line >= selected_line_)) ? 0 : new_line, 270 SetSelectedLine(((count < 0) && (new_line >= selected_line_)) ? 0 : new_line,
270 false); 271 false, false);
271 } 272 }
272 273
273 void AutocompletePopupModel::TryDeletingCurrentItem() { 274 void AutocompletePopupModel::TryDeletingCurrentItem() {
274 // We could use InfoForCurrentSelection() here, but it seems better to try 275 // We could use InfoForCurrentSelection() here, but it seems better to try
275 // and shift-delete the actual selection, rather than any "in progress, not 276 // and shift-delete the actual selection, rather than any "in progress, not
276 // yet visible" one. 277 // yet visible" one.
277 if (selected_line_ == kNoMatch) 278 if (selected_line_ == kNoMatch)
278 return; 279 return;
279 280
280 // Cancel the query so the matches don't change on the user. 281 // Cancel the query so the matches don't change on the user.
281 controller_->Stop(false); 282 controller_->Stop(false);
282 283
283 const AutocompleteMatch& match = 284 const AutocompleteMatch& match =
284 controller_->result().match_at(selected_line_); 285 controller_->result().match_at(selected_line_);
285 if (match.deletable) { 286 if (match.deletable) {
286 const size_t selected_line = selected_line_; 287 const size_t selected_line = selected_line_;
287 controller_->DeleteMatch(match); // This may synchronously notify us that 288 const bool was_temporary_text = !manually_selected_match_.empty();
288 // the results have changed. 289 GURL old_url;
290
291 // If the user tries to delete a match, which is not manually selected,
292 // then we should not re-select it if it's not deleted at all.
293 // Otherwise it will be selected as temporary text unexpectedly.
294 // We can check the url of the default match before and after calling
295 // |controller->DeleteMatch()| to see if it's actually deleted or not.
296 // But if the match is manually selected, then we should always re-select
297 // the selected line manually no matter if the match is actually deleted
298 // or not, to make sure we stay in the temporary text mode.
299 if (!was_temporary_text)
300 old_url = controller_->result().match_at(selected_line).destination_url;
301
302 // This may synchronously notify us that the results have changed. And may
Peter Kasting 2011/01/25 21:56:44 Nit: Given the DCHECK in DeleteMatch(), it would p
James Su 2011/01/25 22:32:37 Done.
303 // cause edit model to revert the temporary text automatically.
304 controller_->DeleteMatch(match);
289 const AutocompleteResult& result = controller_->result(); 305 const AutocompleteResult& result = controller_->result();
290 if (!result.empty()) { 306 if (!result.empty() &&
307 (was_temporary_text || selected_line != selected_line_ ||
308 old_url != result.match_at(selected_line).destination_url)) {
291 // Move the selection to the next choice after the deleted one. 309 // Move the selection to the next choice after the deleted one.
292 // SetSelectedLine() will clamp to take care of the case where we deleted 310 // SetSelectedLine() will clamp to take care of the case where we deleted
293 // the last item. 311 // the last item.
294 // TODO(pkasting): Eventually the controller should take care of this 312 // TODO(pkasting): Eventually the controller should take care of this
295 // before notifying us, reducing flicker. At that point the check for 313 // before notifying us, reducing flicker. At that point the check for
296 // deletability can move there too. 314 // deletability can move there too.
297 SetSelectedLine(selected_line, false); 315 SetSelectedLine(selected_line, false, true);
298 } 316 }
299 } 317 }
300 } 318 }
301 319
302 void AutocompletePopupModel::Observe(NotificationType type, 320 void AutocompletePopupModel::Observe(NotificationType type,
303 const NotificationSource& source, 321 const NotificationSource& source,
304 const NotificationDetails& details) { 322 const NotificationDetails& details) {
305 DCHECK_EQ(NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED, 323 DCHECK_EQ(NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED,
306 type.value); 324 type.value);
307 325
308 const AutocompleteResult* result = 326 const AutocompleteResult* result =
309 Details<const AutocompleteResult>(details).ptr(); 327 Details<const AutocompleteResult>(details).ptr();
310 selected_line_ = result->default_match() == result->end() ? 328 selected_line_ = result->default_match() == result->end() ?
311 kNoMatch : static_cast<size_t>(result->default_match() - result->begin()); 329 kNoMatch : static_cast<size_t>(result->default_match() - result->begin());
312 // There had better not be a nonempty result set with no default match. 330 // There had better not be a nonempty result set with no default match.
313 CHECK((selected_line_ != kNoMatch) || result->empty()); 331 CHECK((selected_line_ != kNoMatch) || result->empty());
332 manually_selected_match_.Clear();
314 // If we're going to trim the window size to no longer include the hovered 333 // If we're going to trim the window size to no longer include the hovered
315 // line, turn hover off. Practically, this shouldn't happen, but it 334 // line, turn hover off. Practically, this shouldn't happen, but it
316 // doesn't hurt to be defensive. 335 // doesn't hurt to be defensive.
317 if ((hovered_line_ != kNoMatch) && (result->size() <= hovered_line_)) 336 if ((hovered_line_ != kNoMatch) && (result->size() <= hovered_line_))
318 SetHoveredLine(kNoMatch); 337 SetHoveredLine(kNoMatch);
319 338
320 const bool was_open = view_->IsOpen(); 339 const bool was_open = view_->IsOpen();
321 view_->UpdatePopupAppearance(); 340 view_->UpdatePopupAppearance();
322 if (view_->IsOpen()) 341 if (view_->IsOpen())
323 edit_model_->PopupBoundsChangedTo(view_->GetTargetBounds()); 342 edit_model_->PopupBoundsChangedTo(view_->GetTargetBounds());
324 else if (was_open) 343 else if (was_open)
325 edit_model_->OnPopupClosed(); 344 edit_model_->OnPopupClosed();
326 } 345 }
327 346
328 const SkBitmap* AutocompletePopupModel::GetSpecialIconForMatch( 347 const SkBitmap* AutocompletePopupModel::GetSpecialIconForMatch(
329 const AutocompleteMatch& match) const { 348 const AutocompleteMatch& match) const {
330 if (!match.template_url || !match.template_url->IsExtensionKeyword()) 349 if (!match.template_url || !match.template_url->IsExtensionKeyword())
331 return NULL; 350 return NULL;
332 351
333 return &profile_->GetExtensionService()->GetOmniboxPopupIcon( 352 return &profile_->GetExtensionService()->GetOmniboxPopupIcon(
334 match.template_url->GetExtensionId()); 353 match.template_url->GetExtensionId());
335 } 354 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698