1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_MODEL_H_
6#define CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_MODEL_H_
7
8#include "base/basictypes.h"
9#include "base/observer_list.h"
10#include "chrome/browser/autocomplete/autocomplete_controller.h"
11#include "chrome/browser/autocomplete/autocomplete_result.h"
12#include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
13
14class OmniboxPopupModelObserver;
15class OmniboxPopupView;
16
17namespace gfx {
18class Image;
19}
20
21class OmniboxPopupModel {
22 public:
23  // See selected_line_state_ for details.
24  enum LineState {
25    NORMAL = 0,
26    KEYWORD
27  };
28
29  OmniboxPopupModel(OmniboxPopupView* popup_view, OmniboxEditModel* edit_model);
30  ~OmniboxPopupModel();
31
32  // Computes the maximum width, in pixels, that can be allocated for the two
33  // parts of an autocomplete result, i.e. the contents and the description.
34  static void ComputeMatchMaxWidths(int contents_width,
35                                    int separator_width,
36                                    int description_width,
37                                    int available_width,
38                                    bool allow_shrinking_contents,
39                                    int* contents_max_width,
40                                    int* description_max_width);
41
42  // Returns true if the popup is currently open.
43  bool IsOpen() const;
44
45  OmniboxPopupView* view() const { return view_; }
46
47  // Returns the AutocompleteController used by this popup.
48  AutocompleteController* autocomplete_controller() const {
49    return edit_model_->autocomplete_controller();
50  }
51
52  const AutocompleteResult& result() const {
53    return autocomplete_controller()->result();
54  }
55
56  size_t hovered_line() const { return hovered_line_; }
57
58  // Call to change the hovered line.  |line| should be within the range of
59  // valid lines (to enable hover) or kNoMatch (to disable hover).
60  void SetHoveredLine(size_t line);
61
62  size_t selected_line() const { return selected_line_; }
63
64  LineState selected_line_state() const { return selected_line_state_; }
65
66  // Call to change the selected line.  This will update all state and repaint
67  // the necessary parts of the window, as well as updating the edit with the
68  // new temporary text.  |line| will be clamped to the range of valid lines.
69  // |reset_to_default| is true when the selection is being reset back to the
70  // default match, and thus there is no temporary text (and no
71  // |manually_selected_match_|). If |force| is true then the selected line will
72  // be updated forcibly even if the |line| is same as the current selected
73  // line.
74  // NOTE: This assumes the popup is open, and thus both old and new values for
75  // the selected line should not be kNoMatch.
76  void SetSelectedLine(size_t line, bool reset_to_default, bool force);
77
78  // Called when the user hits escape after arrowing around the popup.  This
79  // will change the selected line back to the default match and redraw.
80  void ResetToDefaultMatch();
81
82  // Immediately updates and opens the popup if necessary, then moves the
83  // current selection down (|count| > 0) or up (|count| < 0), clamping to the
84  // first or last result if necessary.  If |count| == 0, the selection will be
85  // unchanged, but the popup will still redraw and modify the text in the
86  // OmniboxEditModel.
87  void Move(int count);
88
89  // If the selected line has both a normal match and a keyword match, this can
90  // be used to choose which to select. It is an error to call this when the
91  // selected line does not have both matches (or there is no selection).
92  void SetSelectedLineState(LineState state);
93
94  // Called when the user hits shift-delete.  This should determine if the item
95  // can be removed from history, and if so, remove it and update the popup.
96  void TryDeletingCurrentItem();
97
98  // If |match| is from an extension, returns the extension icon; otherwise
99  // returns an empty Image.
100  gfx::Image GetIconIfExtensionMatch(const AutocompleteMatch& match) const;
101
102  // The match the user has manually chosen, if any.
103  const AutocompleteResult::Selection& manually_selected_match() const {
104    return manually_selected_match_;
105  }
106
107  // Invoked from the edit model any time the result set of the controller
108  // changes.
109  void OnResultChanged();
110
111  // Add and remove observers.
112  void AddObserver(OmniboxPopupModelObserver* observer);
113  void RemoveObserver(OmniboxPopupModelObserver* observer);
114
115  // The token value for selected_line_, hover_line_ and functions dealing with
116  // a "line number" that indicates "no line".
117  static const size_t kNoMatch;
118
119 private:
120  OmniboxPopupView* view_;
121
122  OmniboxEditModel* edit_model_;
123
124  // The line that's currently hovered.  If we're not drawing a hover rect,
125  // this will be kNoMatch, even if the cursor is over the popup contents.
126  size_t hovered_line_;
127
128  // The currently selected line.  This is kNoMatch when nothing is selected,
129  // which should only be true when the popup is closed.
130  size_t selected_line_;
131
132  // If the selected line has both a normal match and a keyword match, this
133  // determines whether the normal match (if NORMAL) or the keyword match
134  // (if KEYWORD) is selected.
135  LineState selected_line_state_;
136
137  // The match the user has manually chosen, if any.
138  AutocompleteResult::Selection manually_selected_match_;
139
140  // Observers.
141  ObserverList<OmniboxPopupModelObserver> observers_;
142
143  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupModel);
144};
145
146#endif  // CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_MODEL_H_
147