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
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_
6#define CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_
7#pragma once
8
9#include <set>
10#include <string>
11
12#include "base/basictypes.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/memory/scoped_vector.h"
15#include "base/string16.h"
16#include "base/task.h"
17#include "base/timer.h"
18#include "chrome/browser/instant/instant_commit_type.h"
19#include "chrome/browser/instant/instant_loader_delegate.h"
20#include "chrome/browser/search_engines/template_url_id.h"
21#include "chrome/common/instant_types.h"
22#include "content/common/page_transition_types.h"
23#include "googleurl/src/gurl.h"
24#include "ui/gfx/native_widget_types.h"
25#include "ui/gfx/rect.h"
26
27struct AutocompleteMatch;
28class InstantDelegate;
29class InstantLoader;
30class InstantLoaderManager;
31class InstantTest;
32class PrefService;
33class Profile;
34class TabContents;
35class TabContentsWrapper;
36class TemplateURL;
37
38// InstantController maintains a TabContents that is intended to give a preview
39// of a URL. InstantController is owned by Browser.
40//
41// At any time the TabContents maintained by InstantController may be destroyed
42// by way of |DestroyPreviewContents|, which results in |HideInstant| being
43// invoked on the delegate. Similarly the preview may be committed at any time
44// by invoking |CommitCurrentPreview|, which results in |CommitInstant|
45// being invoked on the delegate.
46class InstantController : public InstantLoaderDelegate {
47 public:
48  // Amount of time to wait before starting the instant animation.
49  static const int kAutoCommitPauseTimeMS = 1000;
50  // Duration of the instant animation in which the colors change.
51  static const int kAutoCommitFadeInTimeMS = 300;
52
53  InstantController(Profile* profile, InstantDelegate* delegate);
54  ~InstantController();
55
56  // Registers instant related preferences.
57  static void RegisterUserPrefs(PrefService* prefs);
58
59  // Records instant metrics.
60  static void RecordMetrics(Profile* profile);
61
62  // Returns true if instant is enabled.
63  static bool IsEnabled(Profile* profile);
64
65  // Enables instant.
66  static void Enable(Profile* profile);
67
68  // Disables instant.
69  static void Disable(Profile* profile);
70
71  // Accepts the currently showing instant preview, if any, and returns true.
72  // Returns false if there is no instant preview showing.
73  static bool CommitIfCurrent(InstantController* controller);
74
75  // Invoked as the user types in the omnibox with the url to navigate to.  If
76  // the url is empty and there is a preview TabContents it is destroyed. If url
77  // is non-empty and the preview TabContents has not been created it is
78  // created. If |verbatim| is true search results are shown for |user_text|
79  // rather than the best guess as to what the search thought the user meant.
80  // |verbatim| only matters if the AutocompleteMatch is for a search engine
81  // that supports instant.
82  void Update(TabContentsWrapper* tab_contents,
83              const AutocompleteMatch& match,
84              const string16& user_text,
85              bool verbatim,
86              string16* suggested_text);
87
88  // Sets the bounds of the omnibox (in screen coordinates). The bounds are
89  // remembered until the preview is committed or destroyed. This is only used
90  // when showing results for a search provider that supports instant.
91  void SetOmniboxBounds(const gfx::Rect& bounds);
92
93  // Destroys the preview TabContents. Does nothing if the preview TabContents
94  // has not been created.
95  void DestroyPreviewContents();
96
97  // Destroys the current loaders but remains active.
98  void DestroyPreviewContentsAndLeaveActive();
99
100  // Returns true if we're showing the last URL passed to |Update|. If this is
101  // false a commit does not result in committing the last url passed to update.
102  // A return value of false happens if we're in the process of determining if
103  // the page supports instant.
104  bool IsCurrent();
105
106  // Invoked when the user does some gesture that should trigger making the
107  // current previewed page the permanent page.
108  void CommitCurrentPreview(InstantCommitType type);
109
110  // Sets InstantController so that when the mouse is released the preview is
111  // committed.
112  void SetCommitOnMouseUp();
113
114  bool commit_on_mouse_up() const { return commit_on_mouse_up_; }
115
116  // Returns true if the mouse is down as the result of activating the preview
117  // content.
118  bool IsMouseDownFromActivate();
119
120  // The autocomplete edit that was initiating the current instant session has
121  // lost focus. Commit or discard the preview accordingly.
122  void OnAutocompleteLostFocus(gfx::NativeView view_gaining_focus);
123
124  // Releases the preview TabContents passing ownership to the caller. This is
125  // intended to be called when the preview TabContents is committed. This does
126  // not notify the delegate.
127  // WARNING: be sure and invoke CompleteRelease after adding the returned
128  // TabContents to a tabstrip.
129  TabContentsWrapper* ReleasePreviewContents(InstantCommitType type);
130
131  // Does cleanup after the preview contents has been added to the tabstrip.
132  // Invoke this if you explicitly invoke ReleasePreviewContents.
133  void CompleteRelease(TabContents* tab);
134
135  // TabContents the match is being shown for.
136  TabContentsWrapper* tab_contents() const { return tab_contents_; }
137
138  // The preview TabContents; may be null.
139  TabContentsWrapper* GetPreviewContents();
140
141  // Returns true if |Update| has been invoked without a corresponding call to
142  // |DestroyPreviewContents| or |CommitCurrentPreview|.
143  bool is_active() const { return is_active_; }
144
145  // Returns true if the preview TabContents is ready to be displayed. In some
146  // situations this may return false yet GetPreviewContents() returns non-NULL.
147  bool is_displayable() const { return displayable_loader_ != NULL; }
148
149  // Returns the transition type of the last AutocompleteMatch passed to Update.
150  PageTransition::Type last_transition_type() const {
151    return last_transition_type_;
152  }
153
154  // Returns true if we're showing results from a provider that supports the
155  // instant API. See description of |MightSupportInstant| for how this
156  // differs from actual loading state.
157  bool IsShowingInstant();
158
159  // Returns true if we're attempting to use the instant API with the last URL
160  // passed to |Update|. The value of this may change if it turns the provider
161  // doesn't really support the instant API.
162  // The value of |IsShowingInstant| indicates whether what is currently
163  // displayed supports instant, whereas this returns the loading state.  The
164  // state of |IsShowingInstant| differs when transitioning from a non-search
165  // provider to a search provider that supports instant (or the other way
166  // around). For example, if |Update| is passed www.foo.com, followed by a
167  // search string then this returns true, but |IsShowingInstant| returns false
168  // (until the search provider loads, then both return true).
169  bool MightSupportInstant();
170
171  // Returns the URL currently being loaded or shown if everything has finished
172  // loading.
173  GURL GetCurrentURL();
174
175  // InstantLoaderDelegate
176  virtual void InstantStatusChanged(InstantLoader* loader) OVERRIDE;
177  virtual void SetSuggestedTextFor(InstantLoader* loader,
178                                   const string16& text,
179                                   InstantCompleteBehavior behavior) OVERRIDE;
180  virtual gfx::Rect GetInstantBounds() OVERRIDE;
181  virtual bool ShouldCommitInstantOnMouseUp() OVERRIDE;
182  virtual void CommitInstantLoader(InstantLoader* loader) OVERRIDE;
183  virtual void InstantLoaderDoesntSupportInstant(
184      InstantLoader* loader) OVERRIDE;
185  virtual void AddToBlacklist(InstantLoader* loader,
186                              const GURL& url) OVERRIDE;
187
188 private:
189  friend class InstantTest;
190
191  typedef std::set<std::string> HostBlacklist;
192
193  // Updates |displayable_loader_| and if necessary notifies the delegate.
194  void UpdateDisplayableLoader();
195
196  // Returns the TabContents of the pending loader (or NULL). This is only used
197  // for testing.
198  TabContentsWrapper* GetPendingPreviewContents();
199
200  // Returns true if we should update immediately.
201  bool ShouldUpdateNow(TemplateURLID instant_id, const GURL& url);
202
203  // Schedules a delayed update to load the specified url.
204  void ScheduleUpdate(const GURL& url);
205
206  // Invoked from the timer to process the last scheduled url.
207  void ProcessScheduledUpdate();
208
209  // Does the work of processing a change in the status (ready or
210  // http_status_ok) of a loader.
211  void ProcessInstantStatusChanged(InstantLoader* loader);
212
213  // Callback when the |show_timer_| fires. Invokes
214  // |ProcessInstantStatusChanged| with the appropriate arguments.
215  void ShowTimerFired();
216
217  // Updates InstantLoaderManager and its current InstantLoader. This is invoked
218  // internally from Update.
219  void UpdateLoader(const TemplateURL* template_url,
220                    const GURL& url,
221                    PageTransition::Type transition_type,
222                    const string16& user_text,
223                    bool verbatim,
224                    string16* suggested_text);
225
226  // Returns true if a preview should be shown for |match|. If |match| has
227  // a TemplateURL that supports the instant API it is set in |template_url|.
228  bool ShouldShowPreviewFor(const AutocompleteMatch& match,
229                            const TemplateURL** template_url);
230
231  // Marks the specified search engine id as not supporting instant.
232  void BlacklistFromInstant(TemplateURLID id);
233
234  // Returns true if the specified id has been blacklisted from supporting
235  // instant.
236  bool IsBlacklistedFromInstant(TemplateURLID id);
237
238  // Clears the set of search engines blacklisted.
239  void ClearBlacklist();
240
241  // Deletes |loader| after a delay. At the time we determine a site doesn't
242  // want to participate in instant we can't destroy the loader (because
243  // destroying the loader destroys the TabContents and the TabContents is on
244  // the stack). Instead we place the loader in |loaders_to_destroy_| and
245  // schedule a task.
246  void ScheduleDestroy(InstantLoader* loader);
247
248  // Destroys all loaders scheduled for destruction in |ScheduleForDestroy|.
249  void DestroyLoaders();
250
251  // Returns the TemplateURL to use for the specified AutocompleteMatch, or
252  // NULL if there is no TemplateURL for |match|.
253  const TemplateURL* GetTemplateURL(const AutocompleteMatch& match);
254
255  InstantDelegate* delegate_;
256
257  // The TabContents last passed to |Update|.
258  TabContentsWrapper* tab_contents_;
259
260  // See description above getter for details.
261  bool is_active_;
262
263  // The loader that is ready to be displayed.
264  InstantLoader* displayable_loader_;
265
266  // See description above setter.
267  gfx::Rect omnibox_bounds_;
268
269  // See description above CommitOnMouseUp.
270  bool commit_on_mouse_up_;
271
272  // See description above getter.
273  PageTransition::Type last_transition_type_;
274
275  scoped_ptr<InstantLoaderManager> loader_manager_;
276
277  // The IDs of any search engines that don't support instant. We assume all
278  // search engines support instant, but if we determine an engine doesn't
279  // support instant it is added to this list. The list is cleared out on every
280  // reset/commit.
281  std::set<TemplateURLID> blacklisted_ids_;
282
283  // Timer used to delay calls to |UpdateLoader|.
284  base::OneShotTimer<InstantController> update_timer_;
285
286  // Timer used to delay showing loaders whose status isn't ok.
287  base::OneShotTimer<InstantController> show_timer_;
288
289  // Used by ScheduleForDestroy; see it for details.
290  ScopedRunnableMethodFactory<InstantController> destroy_factory_;
291
292  // URL last pased to ScheduleUpdate.
293  GURL scheduled_url_;
294
295  // List of InstantLoaders to destroy. See ScheduleForDestroy for details.
296  ScopedVector<InstantLoader> loaders_to_destroy_;
297
298  // The set of hosts that we don't use instant with. This is shared across all
299  // instances and only maintained for the current session.
300  static HostBlacklist* host_blacklist_;
301
302  DISALLOW_COPY_AND_ASSIGN(InstantController);
303};
304
305#endif  // CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_
306