[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
blundell | 7dbd379 | 2015-08-05 15:14:19 | [diff] [blame] | 5 | #ifndef COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_POPUP_MODEL_H_ |
| 6 | #define COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_POPUP_MODEL_H_ |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 7 | |
avi | f57136c1 | 2015-12-25 23:27:45 | [diff] [blame] | 8 | #include <stddef.h> |
Dave Schuyler | c7affc03 | 2018-04-26 20:43:37 | [diff] [blame] | 9 | #include <map> |
avi | f57136c1 | 2015-12-25 23:27:45 | [diff] [blame] | 10 | |
avi | f57136c1 | 2015-12-25 23:27:45 | [diff] [blame] | 11 | #include "base/macros.h" |
Tommy C. Li | 3b9185c74 | 2017-08-30 18:40:32 | [diff] [blame] | 12 | #include "base/memory/weak_ptr.h" |
[email protected] | 55f3982 | 2013-07-10 02:32:14 | [diff] [blame] | 13 | #include "base/observer_list.h" |
Tommy C. Li | 491455c | 2017-09-07 00:02:14 | [diff] [blame] | 14 | #include "build/build_config.h" |
blundell | 2102f7c | 2015-07-09 10:00:53 | [diff] [blame] | 15 | #include "components/omnibox/browser/autocomplete_controller.h" |
| 16 | #include "components/omnibox/browser/autocomplete_result.h" |
blundell | 7dbd379 | 2015-08-05 15:14:19 | [diff] [blame] | 17 | #include "components/omnibox/browser/omnibox_edit_model.h" |
dschuyler | f32bc3a | 2015-05-22 06:29:16 | [diff] [blame] | 18 | #include "third_party/skia/include/core/SkBitmap.h" |
Tommy C. Li | 3b9185c74 | 2017-08-30 18:40:32 | [diff] [blame] | 19 | #include "ui/gfx/image/image.h" |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 20 | |
[email protected] | 55f3982 | 2013-07-10 02:32:14 | [diff] [blame] | 21 | class OmniboxPopupModelObserver; |
[email protected] | b2544aa9 | 2012-06-21 04:20:09 | [diff] [blame] | 22 | class OmniboxPopupView; |
Tommy C. Li | a240bde | 2018-01-04 22:08:35 | [diff] [blame] | 23 | class GURL; |
[email protected] | e8476c99 | 2012-08-20 20:27:59 | [diff] [blame] | 24 | |
| 25 | namespace gfx { |
| 26 | class Image; |
| 27 | } |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 28 | |
[email protected] | b2544aa9 | 2012-06-21 04:20:09 | [diff] [blame] | 29 | class OmniboxPopupModel { |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 30 | public: |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 31 | // See selected_line_state_ for details. |
| 32 | enum LineState { |
| 33 | NORMAL = 0, |
Kevin Bailey | dbcdc35 | 2018-04-27 13:57:14 | [diff] [blame] | 34 | KEYWORD, |
| 35 | TAB_SWITCH |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 36 | }; |
| 37 | |
[email protected] | 5af9bc8 | 2012-06-29 00:53:48 | [diff] [blame] | 38 | OmniboxPopupModel(OmniboxPopupView* popup_view, OmniboxEditModel* edit_model); |
Tommy C. Li | c9c838d | 2018-06-01 00:02:56 | [diff] [blame] | 39 | ~OmniboxPopupModel(); |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 40 | |
[email protected] | 5ef9790 | 2014-03-20 19:36:24 | [diff] [blame] | 41 | // Computes the maximum width, in pixels, that can be allocated for the two |
| 42 | // parts of an autocomplete result, i.e. the contents and the description. |
krb | 78c84b7 | 2016-03-15 14:50:37 | [diff] [blame] | 43 | // |
| 44 | // When |description_on_separate_line| is true, the caller will be displaying |
| 45 | // two separate lines of text, so both contents and description can take up |
| 46 | // the full available width. Otherwise, the contents and description are |
| 47 | // assumed to be on the same line, with a separator between them. |
| 48 | // |
| 49 | // When |allow_shrinking_contents| is true, and the contents and description |
| 50 | // are together on a line without enough space for both, the code tries to |
| 51 | // divide the available space equally between the two, unless this would make |
| 52 | // one or both too narrow. Otherwise, the contents is given as much space as |
| 53 | // it wants and the description gets the remainder. |
[email protected] | 5ef9790 | 2014-03-20 19:36:24 | [diff] [blame] | 54 | static void ComputeMatchMaxWidths(int contents_width, |
| 55 | int separator_width, |
| 56 | int description_width, |
| 57 | int available_width, |
krb | 78c84b7 | 2016-03-15 14:50:37 | [diff] [blame] | 58 | bool description_on_separate_line, |
[email protected] | 5ef9790 | 2014-03-20 19:36:24 | [diff] [blame] | 59 | bool allow_shrinking_contents, |
| 60 | int* contents_max_width, |
| 61 | int* description_max_width); |
| 62 | |
Tommy C. Li | c9c838d | 2018-06-01 00:02:56 | [diff] [blame] | 63 | // Returns true if the popup is currently open. |
| 64 | bool IsOpen() const; |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 65 | |
[email protected] | b2544aa9 | 2012-06-21 04:20:09 | [diff] [blame] | 66 | OmniboxPopupView* view() const { return view_; } |
[email protected] | 6c4e6631 | 2010-08-09 15:18:17 | [diff] [blame] | 67 | |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 68 | // Returns the AutocompleteController used by this popup. |
| 69 | AutocompleteController* autocomplete_controller() const { |
[email protected] | 28b6e25 | 2011-02-16 16:31:27 | [diff] [blame] | 70 | return edit_model_->autocomplete_controller(); |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | const AutocompleteResult& result() const { |
[email protected] | 28b6e25 | 2011-02-16 16:31:27 | [diff] [blame] | 74 | return autocomplete_controller()->result(); |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 75 | } |
| 76 | |
[email protected] | 5af9bc8 | 2012-06-29 00:53:48 | [diff] [blame] | 77 | size_t selected_line() const { return selected_line_; } |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 78 | |
[email protected] | 5af9bc8 | 2012-06-29 00:53:48 | [diff] [blame] | 79 | LineState selected_line_state() const { return selected_line_state_; } |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 80 | |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 81 | // Call to change the selected line. This will update all state and repaint |
| 82 | // the necessary parts of the window, as well as updating the edit with the |
[email protected] | 6181e4bd | 2010-08-09 23:22:43 | [diff] [blame] | 83 | // new temporary text. |line| will be clamped to the range of valid lines. |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 84 | // |reset_to_default| is true when the selection is being reset back to the |
Kevin Bailey | a60106e | 2017-09-08 21:41:36 | [diff] [blame] | 85 | // default match, and thus there is no temporary text (and not |
| 86 | // |has_selected_match_|). If |force| is true then the selected line will |
[email protected] | 4fc461e | 2011-01-26 17:41:48 | [diff] [blame] | 87 | // be updated forcibly even if the |line| is same as the current selected |
| 88 | // line. |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 89 | // NOTE: This assumes the popup is open, and thus both old and new values for |
| 90 | // the selected line should not be kNoMatch. |
[email protected] | 4fc461e | 2011-01-26 17:41:48 | [diff] [blame] | 91 | void SetSelectedLine(size_t line, bool reset_to_default, bool force); |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 92 | |
| 93 | // Called when the user hits escape after arrowing around the popup. This |
| 94 | // will change the selected line back to the default match and redraw. |
| 95 | void ResetToDefaultMatch(); |
| 96 | |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 97 | // Immediately updates and opens the popup if necessary, then moves the |
| 98 | // current selection down (|count| > 0) or up (|count| < 0), clamping to the |
| 99 | // first or last result if necessary. If |count| == 0, the selection will be |
| 100 | // unchanged, but the popup will still redraw and modify the text in the |
[email protected] | fbdc423 | 2012-06-24 15:28:37 | [diff] [blame] | 101 | // OmniboxEditModel. |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 102 | void Move(int count); |
| 103 | |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 104 | // If the selected line has both a normal match and a keyword match, this can |
pkasting | 19b75b7 | 2015-04-21 22:42:28 | [diff] [blame] | 105 | // be used to choose which to select. This allows the user to toggle between |
| 106 | // normal and keyword mode with tab/shift-tab without rerunning autocomplete |
| 107 | // or disturbing other popup state, which in turn is an important part of |
| 108 | // supporting the use of tab to do both tab-to-search and |
| 109 | // tab-to-traverse-dropdown. |
| 110 | // |
| 111 | // It is an error to call this when the selected line does not have both |
| 112 | // matches (or there is no selection). |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 113 | void SetSelectedLineState(LineState state); |
| 114 | |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 115 | // Called when the user hits shift-delete. This should determine if the item |
| 116 | // can be removed from history, and if so, remove it and update the popup. |
| 117 | void TryDeletingCurrentItem(); |
| 118 | |
[email protected] | 7daef464 | 2014-07-29 07:44:38 | [diff] [blame] | 119 | // Returns true if the destination URL of the match is bookmarked. |
| 120 | bool IsStarredMatch(const AutocompleteMatch& match) const; |
| 121 | |
Kevin Bailey | a60106e | 2017-09-08 21:41:36 | [diff] [blame] | 122 | // The user has manually selected a match. |
| 123 | bool has_selected_match() { return has_selected_match_; } |
[email protected] | e1fe3da | 2010-10-08 20:32:50 | [diff] [blame] | 124 | |
[email protected] | bb52764 | 2011-02-14 16:47:26 | [diff] [blame] | 125 | // Invoked from the edit model any time the result set of the controller |
| 126 | // changes. |
| 127 | void OnResultChanged(); |
| 128 | |
[email protected] | 55f3982 | 2013-07-10 02:32:14 | [diff] [blame] | 129 | // Add and remove observers. |
| 130 | void AddObserver(OmniboxPopupModelObserver* observer); |
| 131 | void RemoveObserver(OmniboxPopupModelObserver* observer); |
| 132 | |
Dave Schuyler | c7affc03 | 2018-04-26 20:43:37 | [diff] [blame] | 133 | // Lookup the bitmap for |result_index|. Returns nullptr if not found. |
| 134 | const SkBitmap* RichSuggestionBitmapAt(int result_index) const; |
dschuyler | f32bc3a | 2015-05-22 06:29:16 | [diff] [blame] | 135 | // Stores the image in a local data member and schedules a repaint. |
Dave Schuyler | c7affc03 | 2018-04-26 20:43:37 | [diff] [blame] | 136 | void SetRichSuggestionBitmap(int result_index, const SkBitmap& bitmap); |
dschuyler | f32bc3a | 2015-05-22 06:29:16 | [diff] [blame] | 137 | |
Tommy C. Li | 491455c | 2017-09-07 00:02:14 | [diff] [blame] | 138 | #if !defined(OS_ANDROID) && !defined(OS_IOS) |
| 139 | // Gets the icon for the match index. |
| 140 | gfx::Image GetMatchIcon(const AutocompleteMatch& match, |
| 141 | SkColor vector_icon_color); |
| 142 | #endif |
| 143 | |
Kevin Bailey | dbcdc35 | 2018-04-27 13:57:14 | [diff] [blame] | 144 | // Helper function to see if current selection has button and can accept |
| 145 | // the tab key. |
| 146 | bool SelectedLineHasTabMatch(); |
| 147 | |
Justin Donnelly | ce9d1bf | 2017-08-10 16:24:55 | [diff] [blame] | 148 | // The token value for selected_line_ and functions dealing with a "line |
| 149 | // number" that indicates "no line". |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 150 | static const size_t kNoMatch; |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 151 | |
| 152 | private: |
Tommy C. Li | 491455c | 2017-09-07 00:02:14 | [diff] [blame] | 153 | void OnFaviconFetched(const GURL& page_url, const gfx::Image& icon); |
Tommy C. Li | 3b9185c74 | 2017-08-30 18:40:32 | [diff] [blame] | 154 | |
Dave Schuyler | c7affc03 | 2018-04-26 20:43:37 | [diff] [blame] | 155 | std::map<int, SkBitmap> rich_suggestion_bitmaps_; |
dschuyler | f32bc3a | 2015-05-22 06:29:16 | [diff] [blame] | 156 | |
[email protected] | b2544aa9 | 2012-06-21 04:20:09 | [diff] [blame] | 157 | OmniboxPopupView* view_; |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 158 | |
[email protected] | fbdc423 | 2012-06-24 15:28:37 | [diff] [blame] | 159 | OmniboxEditModel* edit_model_; |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 160 | |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 161 | // The currently selected line. This is kNoMatch when nothing is selected, |
| 162 | // which should only be true when the popup is closed. |
| 163 | size_t selected_line_; |
| 164 | |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 165 | // If the selected line has both a normal match and a keyword match, this |
| 166 | // determines whether the normal match (if NORMAL) or the keyword match |
Kevin Bailey | dbcdc35 | 2018-04-27 13:57:14 | [diff] [blame] | 167 | // (if KEYWORD) is selected. Likewise, if the selected line has a normal |
| 168 | // match and a tab switch match, this determines whether the tab switch match |
| 169 | // (if TAB_SWITCH) is selected. |
[email protected] | 3cb0f8d9 | 2012-02-29 05:43:34 | [diff] [blame] | 170 | LineState selected_line_state_; |
| 171 | |
Kevin Bailey | 367d5b8 | 2018-06-29 22:27:00 | [diff] [blame] | 172 | // When a result changes, this informs of the URL in the previously selected |
| 173 | // suggestion whose tab switch button was focused, so that we may compare |
| 174 | // if equal. |
| 175 | GURL old_focused_url_; |
| 176 | |
Kevin Bailey | a60106e | 2017-09-08 21:41:36 | [diff] [blame] | 177 | // The user has manually selected a match. |
| 178 | bool has_selected_match_; |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 179 | |
[email protected] | 55f3982 | 2013-07-10 02:32:14 | [diff] [blame] | 180 | // Observers. |
brettw | d195c95 | 2015-06-02 17:31:12 | [diff] [blame] | 181 | base::ObserverList<OmniboxPopupModelObserver> observers_; |
[email protected] | 55f3982 | 2013-07-10 02:32:14 | [diff] [blame] | 182 | |
Tommy C. Li | 3b9185c74 | 2017-08-30 18:40:32 | [diff] [blame] | 183 | base::WeakPtrFactory<OmniboxPopupModel> weak_factory_; |
| 184 | |
[email protected] | b2544aa9 | 2012-06-21 04:20:09 | [diff] [blame] | 185 | DISALLOW_COPY_AND_ASSIGN(OmniboxPopupModel); |
[email protected] | f387f1b | 2009-02-27 14:49:51 | [diff] [blame] | 186 | }; |
| 187 | |
blundell | 7dbd379 | 2015-08-05 15:14:19 | [diff] [blame] | 188 | #endif // COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_POPUP_MODEL_H_ |