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) 4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// static 4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void OmniboxPopupModel::ComputeMatchMaxWidths(int contents_width, 4423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int separator_width, 4523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int description_width, 4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int available_width, 4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) bool allow_shrinking_contents, 4823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int* contents_max_width, 4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int* description_max_width) { 5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (available_width <= 0) { 5123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *contents_max_width = 0; 5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *description_max_width = 0; 5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return; 5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 5623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *contents_max_width = contents_width; 5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *description_max_width = description_width; 5823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 5923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // If the description is empty, the contents can get the full width. 6023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (!description_width) 6123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return; 6223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 6323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) available_width -= separator_width; 6423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 6523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (contents_width + description_width > available_width) { 6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (allow_shrinking_contents) { 6723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // Try to split the available space fairly between contents and 6823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // description (if one wants less than half, give it all it wants and 6923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // give the other the remaining space; otherwise, give each half). 7023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // However, if this makes the contents too narrow to show a significant 7123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // amount of information, give the contents more space. 7223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *contents_max_width = std::max( 7323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) (available_width + 1) / 2, available_width - description_width); 7423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 7523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const int kMinimumContentsWidth = 300; 7623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *contents_max_width = std::min( 7723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::max(*contents_max_width, kMinimumContentsWidth), contents_width); 7823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 7923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 8023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // Give the description the remaining space, unless this makes it too small 8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // to display anything meaningful, in which case just hide the description 8223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // and let the contents take up the whole width. 8323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *description_max_width = available_width - *contents_max_width; 8423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const int kMinimumDescriptionWidth = 75; 8523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (*description_max_width < 8623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::min(description_width, kMinimumDescriptionWidth)) { 8723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *description_max_width = 0; 8823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) *contents_max_width = contents_width; 8923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 9223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxPopupModel::IsOpen() const { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return view_->IsOpen(); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::SetHoveredLine(size_t line) { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool is_disabling = (line == kNoMatch); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(is_disabling || (line < result().size())); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line == hovered_line_) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Nothing to do 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure the old hovered line is redrawn. No need to redraw the selected 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // line since selection overrides hover so the appearance won't change. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((hovered_line_ != kNoMatch) && (hovered_line_ != selected_line_)) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->InvalidateLine(hovered_line_); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Change the hover to the new line. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hovered_line_ = line; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_disabling && (hovered_line_ != selected_line_)) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->InvalidateLine(hovered_line_); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::SetSelectedLine(size_t line, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool reset_to_default, 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool force) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteResult& result = this->result(); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result.empty()) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cancel the query so the matches don't change on the user. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) autocomplete_controller()->Stop(false); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = std::min(line, result.size() - 1); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteMatch& match = result.match_at(line); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reset_to_default) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manually_selected_match_.Clear(); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Track the user's selection until they cancel it. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manually_selected_match_.destination_url = match.destination_url; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manually_selected_match_.provider_affinity = match.provider; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manually_selected_match_.is_history_what_you_typed_match = 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match.is_history_what_you_typed_match; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line == selected_line_ && !force) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Nothing else to do. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to update |selected_line_state_| and |selected_line_| before 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // calling InvalidateLine(), since it will check them to determine how to 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // draw. We also need to update |selected_line_| before calling 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // OnPopupDataChanged(), so that when the edit notifies its controller that 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // something has changed, the controller can get the correct updated data. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: We should never reach here with no selected line; the same code that 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // opened the popup and made it possible to get here should have also set a 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // selected line. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(selected_line_ != kNoMatch); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL current_destination(result.match_at(selected_line_).destination_url); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t prev_selected_line = selected_line_; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_line_state_ = NORMAL; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_line_ = line; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->InvalidateLine(prev_selected_line); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->InvalidateLine(selected_line_); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update the edit with the new data for this match. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(pkasting): If |selected_line_| moves to the controller, this can be 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // eliminated and just become a call to the observer on the edit. 160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 keyword; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_keyword_hint; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match.GetKeywordUIState(edit_model_->profile(), &keyword, &is_keyword_hint); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reset_to_default) { 165ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch edit_model_->OnPopupDataChanged(match.inline_autocompletion, NULL, 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keyword, is_keyword_hint); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) edit_model_->OnPopupDataChanged(match.fill_into_edit, ¤t_destination, 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keyword, is_keyword_hint); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Repaint old and new selected lines immediately, so that the edit doesn't 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // appear to update [much] faster than the popup. 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->PaintUpdatesNow(); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::ResetToDefaultMatch() { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteResult& result = this->result(); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!result.empty()); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetSelectedLine(result.default_match() - result.begin(), true, false); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->OnDragCanceled(); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::Move(int count) { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteResult& result = this->result(); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result.empty()) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The user is using the keyboard to change the selection, so stop tracking 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // hover. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetHoveredLine(kNoMatch); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clamp the new line to [0, result_.count() - 1]. 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t new_line = selected_line_ + count; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetSelectedLine(((count < 0) && (new_line >= selected_line_)) ? 0 : new_line, 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false, false); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::SetSelectedLineState(LineState state) { 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!result().empty()); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(kNoMatch, selected_line_); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteMatch& match = result().match_at(selected_line_); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(match.associated_keyword.get()); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_line_state_ = state; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->InvalidateLine(selected_line_); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::TryDeletingCurrentItem() { 211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // We could use GetInfoForCurrentText() here, but it seems better to try 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and shift-delete the actual selection, rather than any "in progress, not 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // yet visible" one. 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (selected_line_ == kNoMatch) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cancel the query so the matches don't change on the user. 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) autocomplete_controller()->Stop(false); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteMatch& match = result().match_at(selected_line_); 221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (match.SupportsDeletion()) { 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t selected_line = selected_line_; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool was_temporary_text = !manually_selected_match_.empty(); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will synchronously notify both the edit and us that the results 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have changed, causing both to revert to the default match. 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) autocomplete_controller()->DeleteMatch(match); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteResult& result = this->result(); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!result.empty() && 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (was_temporary_text || selected_line != selected_line_)) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Move the selection to the next choice after the deleted one. 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SetSelectedLine() will clamp to take care of the case where we deleted 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the last item. 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(pkasting): Eventually the controller should take care of this 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // before notifying us, reducing flicker. At that point the check for 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // deletability can move there too. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetSelectedLine(selected_line, false, true); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Image OmniboxPopupModel::GetIconIfExtensionMatch( 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteMatch& match) const { 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile = edit_model_->profile(); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TemplateURL* template_url = match.GetTemplateURL(profile, false); 2461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (template_url && 2471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) { 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return extensions::OmniboxAPI::Get(profile)->GetOmniboxPopupIcon( 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) template_url->GetExtensionId()); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Image(); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupModel::OnResultChanged() { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteResult& result = this->result(); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_line_ = result.default_match() == result.end() ? 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kNoMatch : static_cast<size_t>(result.default_match() - result.begin()); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There had better not be a nonempty result set with no default match. 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK((selected_line_ != kNoMatch) || result.empty()); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manually_selected_match_.Clear(); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_line_state_ = NORMAL; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we're going to trim the window size to no longer include the hovered 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // line, turn hover off. Practically, this shouldn't happen, but it 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // doesn't hurt to be defensive. 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((hovered_line_ != kNoMatch) && (result.size() <= hovered_line_)) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetHoveredLine(kNoMatch); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bool popup_was_open = view_->IsOpen(); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view_->UpdatePopupAppearance(); 2707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // If popup has just been shown or hidden, notify observers. 2717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (view_->IsOpen() != popup_was_open) { 2727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch FOR_EACH_OBSERVER(OmniboxPopupModelObserver, observers_, 2737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch OnOmniboxPopupShownOrHidden()); 2747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 2757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 2767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 2777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OmniboxPopupModel::AddObserver(OmniboxPopupModelObserver* observer) { 2787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch observers_.AddObserver(observer); 2797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 2807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 2817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid OmniboxPopupModel::RemoveObserver(OmniboxPopupModelObserver* observer) { 2827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch observers_.RemoveObserver(observer); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 284