omnibox_popup_model.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_match.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/search_engines/template_url.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/search_engines/template_url_service.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/search_engines/template_url_service_factory.h"
177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/ui/omnibox/omnibox_popup_model_observer.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_popup_view.h"
19ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "third_party/icu/source/common/unicode/ubidi.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/image/image.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxPopupModel
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t OmniboxPopupModel::kNoMatch = -1;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxPopupModel::OmniboxPopupModel(
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OmniboxPopupView* popup_view,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OmniboxEditModel* edit_model)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : view_(popup_view),
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      edit_model_(edit_model),
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hovered_line_(kNoMatch),
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      selected_line_(kNoMatch),
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      selected_line_state_(NORMAL) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  edit_model->set_popup_model(this);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxPopupModel::~OmniboxPopupModel() {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxPopupModel::IsOpen() const {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return view_->IsOpen();
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::SetHoveredLine(size_t line) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool is_disabling = (line == kNoMatch);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(is_disabling || (line < result().size()));
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (line == hovered_line_)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Nothing to do
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure the old hovered line is redrawn.  No need to redraw the selected
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // line since selection overrides hover so the appearance won't change.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((hovered_line_ != kNoMatch) && (hovered_line_ != selected_line_))
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->InvalidateLine(hovered_line_);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Change the hover to the new line.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hovered_line_ = line;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_disabling && (hovered_line_ != selected_line_))
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->InvalidateLine(hovered_line_);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::SetSelectedLine(size_t line,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        bool reset_to_default,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        bool force) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AutocompleteResult& result = this->result();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result.empty())
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cancel the query so the matches don't change on the user.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  autocomplete_controller()->Stop(false);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  line = std::min(line, result.size() - 1);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AutocompleteMatch& match = result.match_at(line);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reset_to_default) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    manually_selected_match_.Clear();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Track the user's selection until they cancel it.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    manually_selected_match_.destination_url = match.destination_url;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    manually_selected_match_.provider_affinity = match.provider;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    manually_selected_match_.is_history_what_you_typed_match =
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        match.is_history_what_you_typed_match;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (line == selected_line_ && !force)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Nothing else to do.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to update |selected_line_state_| and |selected_line_| before
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // calling InvalidateLine(), since it will check them to determine how to
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // draw.  We also need to update |selected_line_| before calling
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // OnPopupDataChanged(), so that when the edit notifies its controller that
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // something has changed, the controller can get the correct updated data.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: We should never reach here with no selected line; the same code that
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // opened the popup and made it possible to get here should have also set a
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // selected line.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(selected_line_ != kNoMatch);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL current_destination(result.match_at(selected_line_).destination_url);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t prev_selected_line = selected_line_;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selected_line_state_ = NORMAL;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selected_line_ = line;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_->InvalidateLine(prev_selected_line);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_->InvalidateLine(selected_line_);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the edit with the new data for this match.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting): If |selected_line_| moves to the controller, this can be
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // eliminated and just become a call to the observer on the edit.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 keyword;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_keyword_hint;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  match.GetKeywordUIState(edit_model_->profile(), &keyword, &is_keyword_hint);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reset_to_default) {
114ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    edit_model_->OnPopupDataChanged(match.inline_autocompletion, NULL,
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    keyword, is_keyword_hint);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    edit_model_->OnPopupDataChanged(match.fill_into_edit, &current_destination,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    keyword, is_keyword_hint);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Repaint old and new selected lines immediately, so that the edit doesn't
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // appear to update [much] faster than the popup.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_->PaintUpdatesNow();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::ResetToDefaultMatch() {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AutocompleteResult& result = this->result();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!result.empty());
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetSelectedLine(result.default_match() - result.begin(), true, false);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_->OnDragCanceled();
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::Move(int count) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AutocompleteResult& result = this->result();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result.empty())
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The user is using the keyboard to change the selection, so stop tracking
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // hover.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetHoveredLine(kNoMatch);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clamp the new line to [0, result_.count() - 1].
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t new_line = selected_line_ + count;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetSelectedLine(((count < 0) && (new_line >= selected_line_)) ? 0 : new_line,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  false, false);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::SetSelectedLineState(LineState state) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!result().empty());
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(kNoMatch, selected_line_);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AutocompleteMatch& match = result().match_at(selected_line_);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(match.associated_keyword.get());
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selected_line_state_ = state;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_->InvalidateLine(selected_line_);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::TryDeletingCurrentItem() {
160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // We could use GetInfoForCurrentText() here, but it seems better to try
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and shift-delete the actual selection, rather than any "in progress, not
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // yet visible" one.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (selected_line_ == kNoMatch)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cancel the query so the matches don't change on the user.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  autocomplete_controller()->Stop(false);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AutocompleteMatch& match = result().match_at(selected_line_);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (match.deletable) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const size_t selected_line = selected_line_;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const bool was_temporary_text = !manually_selected_match_.empty();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This will synchronously notify both the edit and us that the results
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // have changed, causing both to revert to the default match.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    autocomplete_controller()->DeleteMatch(match);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AutocompleteResult& result = this->result();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!result.empty() &&
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (was_temporary_text || selected_line != selected_line_)) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Move the selection to the next choice after the deleted one.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // SetSelectedLine() will clamp to take care of the case where we deleted
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the last item.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(pkasting): Eventually the controller should take care of this
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // before notifying us, reducing flicker.  At that point the check for
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // deletability can move there too.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetSelectedLine(selected_line, false, true);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Image OmniboxPopupModel::GetIconIfExtensionMatch(
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AutocompleteMatch& match) const {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = edit_model_->profile();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const TemplateURL* template_url = match.GetTemplateURL(profile, false);
1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (template_url &&
1961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) {
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return extensions::OmniboxAPI::Get(profile)->GetOmniboxPopupIcon(
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        template_url->GetExtensionId());
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Image();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::OnResultChanged() {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AutocompleteResult& result = this->result();
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selected_line_ = result.default_match() == result.end() ?
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kNoMatch : static_cast<size_t>(result.default_match() - result.begin());
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There had better not be a nonempty result set with no default match.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK((selected_line_ != kNoMatch) || result.empty());
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  manually_selected_match_.Clear();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selected_line_state_ = NORMAL;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're going to trim the window size to no longer include the hovered
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // line, turn hover off.  Practically, this shouldn't happen, but it
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // doesn't hurt to be defensive.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((hovered_line_ != kNoMatch) && (result.size() <= hovered_line_))
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetHoveredLine(kNoMatch);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool popup_was_open = view_->IsOpen();
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_->UpdatePopupAppearance();
2197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If popup has just been shown or hidden, notify observers.
2207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (view_->IsOpen() != popup_was_open) {
2217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    FOR_EACH_OBSERVER(OmniboxPopupModelObserver, observers_,
2227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      OnOmniboxPopupShownOrHidden());
2237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OmniboxPopupModel::AddObserver(OmniboxPopupModelObserver* observer) {
2277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  observers_.AddObserver(observer);
2287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OmniboxPopupModel::RemoveObserver(OmniboxPopupModelObserver* observer) {
2317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  observers_.RemoveObserver(observer);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
233