// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_
#define CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_
#pragma once
#include <set>
#include <string>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/string16.h"
#include "base/task.h"
#include "base/timer.h"
#include "chrome/browser/instant/instant_commit_type.h"
#include "chrome/browser/instant/instant_loader_delegate.h"
#include "chrome/browser/search_engines/template_url_id.h"
#include "chrome/common/instant_types.h"
#include "content/common/page_transition_types.h"
#include "googleurl/src/gurl.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
struct AutocompleteMatch;
class InstantDelegate;
class InstantLoader;
class InstantLoaderManager;
class InstantTest;
class PrefService;
class Profile;
class TabContents;
class TabContentsWrapper;
class TemplateURL;
// InstantController maintains a TabContents that is intended to give a preview
// of a URL. InstantController is owned by Browser.
//
// At any time the TabContents maintained by InstantController may be destroyed
// by way of |DestroyPreviewContents|, which results in |HideInstant| being
// invoked on the delegate. Similarly the preview may be committed at any time
// by invoking |CommitCurrentPreview|, which results in |CommitInstant|
// being invoked on the delegate.
class InstantController : public InstantLoaderDelegate {
public:
// Amount of time to wait before starting the instant animation.
static const int kAutoCommitPauseTimeMS = 1000;
// Duration of the instant animation in which the colors change.
static const int kAutoCommitFadeInTimeMS = 300;
InstantController(Profile* profile, InstantDelegate* delegate);
~InstantController();
// Registers instant related preferences.
static void RegisterUserPrefs(PrefService* prefs);
// Records instant metrics.
static void RecordMetrics(Profile* profile);
// Returns true if instant is enabled.
static bool IsEnabled(Profile* profile);
// Enables instant.
static void Enable(Profile* profile);
// Disables instant.
static void Disable(Profile* profile);
// Accepts the currently showing instant preview, if any, and returns true.
// Returns false if there is no instant preview showing.
static bool CommitIfCurrent(InstantController* controller);
// Invoked as the user types in the omnibox with the url to navigate to. If
// the url is empty and there is a preview TabContents it is destroyed. If url
// is non-empty and the preview TabContents has not been created it is
// created. If |verbatim| is true search results are shown for |user_text|
// rather than the best guess as to what the search thought the user meant.
// |verbatim| only matters if the AutocompleteMatch is for a search engine
// that supports instant.
void Update(TabContentsWrapper* tab_contents,
const AutocompleteMatch& match,
const string16& user_text,
bool verbatim,
string16* suggested_text);
// Sets the bounds of the omnibox (in screen coordinates). The bounds are
// remembered until the preview is committed or destroyed. This is only used
// when showing results for a search provider that supports instant.
void SetOmniboxBounds(const gfx::Rect& bounds);
// Destroys the preview TabContents. Does nothing if the preview TabContents
// has not been created.
void DestroyPreviewContents();
// Destroys the current loaders but remains active.
void DestroyPreviewContentsAndLeaveActive();
// Returns true if we're showing the last URL passed to |Update|. If this is
// false a commit does not result in committing the last url passed to update.
// A return value of false happens if we're in the process of determining if
// the page supports instant.
bool IsCurrent();
// Invoked when the user does some gesture that should trigger making the
// current previewed page the permanent page.
void CommitCurrentPreview(InstantCommitType type);
// Sets InstantController so that when the mouse is released the preview is
// committed.
void SetCommitOnMouseUp();
bool commit_on_mouse_up() const { return commit_on_mouse_up_; }
// Returns true if the mouse is down as the result of activating the preview
// content.
bool IsMouseDownFromActivate();
// The autocomplete edit that was initiating the current instant session has
// lost focus. Commit or discard the preview accordingly.
void OnAutocompleteLostFocus(gfx::NativeView view_gaining_focus);
// Releases the preview TabContents passing ownership to the caller. This is
// intended to be called when the preview TabContents is committed. This does
// not notify the delegate.
// WARNING: be sure and invoke CompleteRelease after adding the returned
// TabContents to a tabstrip.
TabContentsWrapper* ReleasePreviewContents(InstantCommitType type);
// Does cleanup after the preview contents has been added to the tabstrip.
// Invoke this if you explicitly invoke ReleasePreviewContents.
void CompleteRelease(TabContents* tab);
// TabContents the match is being shown for.
TabContentsWrapper* tab_contents() const { return tab_contents_; }
// The preview TabContents; may be null.
TabContentsWrapper* GetPreviewContents();
// Returns true if |Update| has been invoked without a corresponding call to
// |DestroyPreviewContents| or |CommitCurrentPreview|.
bool is_active() const { return is_active_; }
// Returns true if the preview TabContents is ready to be displayed. In some
// situations this may return false yet GetPreviewContents() returns non-NULL.
bool is_displayable() const { return displayable_loader_ != NULL; }
// Returns the transition type of the last AutocompleteMatch passed to Update.
PageTransition::Type last_transition_type() const {
return last_transition_type_;
}
// Returns true if we're showing results from a provider that supports the
// instant API. See description of |MightSupportInstant| for how this
// differs from actual loading state.
bool IsShowingInstant();
// Returns true if we're attempting to use the instant API with the last URL
// passed to |Update|. The value of this may change if it turns the provider
// doesn't really support the instant API.
// The value of |IsShowingInstant| indicates whether what is currently
// displayed supports instant, whereas this returns the loading state. The
// state of |IsShowingInstant| differs when transitioning from a non-search
// provider to a search provider that supports instant (or the other way
// around). For example, if |Update| is passed www.foo.com, followed by a
// search string then this returns true, but |IsShowingInstant| returns false
// (until the search provider loads, then both return true).
bool MightSupportInstant();
// Returns the URL currently being loaded or shown if everything has finished
// loading.
GURL GetCurrentURL();
// InstantLoaderDelegate
virtual void InstantStatusChanged(InstantLoader* loader) OVERRIDE;
virtual void SetSuggestedTextFor(InstantLoader* loader,
const string16& text,
InstantCompleteBehavior behavior) OVERRIDE;
virtual gfx::Rect GetInstantBounds() OVERRIDE;
virtual bool ShouldCommitInstantOnMouseUp() OVERRIDE;
virtual void CommitInstantLoader(InstantLoader* loader) OVERRIDE;
virtual void InstantLoaderDoesntSupportInstant(
InstantLoader* loader) OVERRIDE;
virtual void AddToBlacklist(InstantLoader* loader,
const GURL& url) OVERRIDE;
private:
friend class InstantTest;
typedef std::set<std::string> HostBlacklist;
// Updates |displayable_loader_| and if necessary notifies the delegate.
void UpdateDisplayableLoader();
// Returns the TabContents of the pending loader (or NULL). This is only used
// for testing.
TabContentsWrapper* GetPendingPreviewContents();
// Returns true if we should update immediately.
bool ShouldUpdateNow(TemplateURLID instant_id, const GURL& url);
// Schedules a delayed update to load the specified url.
void ScheduleUpdate(const GURL& url);
// Invoked from the timer to process the last scheduled url.
void ProcessScheduledUpdate();
// Does the work of processing a change in the status (ready or
// http_status_ok) of a loader.
void ProcessInstantStatusChanged(InstantLoader* loader);
// Callback when the |show_timer_| fires. Invokes
// |ProcessInstantStatusChanged| with the appropriate arguments.
void ShowTimerFired();
// Updates InstantLoaderManager and its current InstantLoader. This is invoked
// internally from Update.
void UpdateLoader(const TemplateURL* template_url,
const GURL& url,
PageTransition::Type transition_type,
const string16& user_text,
bool verbatim,
string16* suggested_text);
// Returns true if a preview should be shown for |match|. If |match| has
// a TemplateURL that supports the instant API it is set in |template_url|.
bool ShouldShowPreviewFor(const AutocompleteMatch& match,
const TemplateURL** template_url);
// Marks the specified search engine id as not supporting instant.
void BlacklistFromInstant(TemplateURLID id);
// Returns true if the specified id has been blacklisted from supporting
// instant.
bool IsBlacklistedFromInstant(TemplateURLID id);
// Clears the set of search engines blacklisted.
void ClearBlacklist();
// Deletes |loader| after a delay. At the time we determine a site doesn't
// want to participate in instant we can't destroy the loader (because
// destroying the loader destroys the TabContents and the TabContents is on
// the stack). Instead we place the loader in |loaders_to_destroy_| and
// schedule a task.
void ScheduleDestroy(InstantLoader* loader);
// Destroys all loaders scheduled for destruction in |ScheduleForDestroy|.
void DestroyLoaders();
// Returns the TemplateURL to use for the specified AutocompleteMatch, or
// NULL if there is no TemplateURL for |match|.
const TemplateURL* GetTemplateURL(const AutocompleteMatch& match);
InstantDelegate* delegate_;
// The TabContents last passed to |Update|.
TabContentsWrapper* tab_contents_;
// See description above getter for details.
bool is_active_;
// The loader that is ready to be displayed.
InstantLoader* displayable_loader_;
// See description above setter.
gfx::Rect omnibox_bounds_;
// See description above CommitOnMouseUp.
bool commit_on_mouse_up_;
// See description above getter.
PageTransition::Type last_transition_type_;
scoped_ptr<InstantLoaderManager> loader_manager_;
// The IDs of any search engines that don't support instant. We assume all
// search engines support instant, but if we determine an engine doesn't
// support instant it is added to this list. The list is cleared out on every
// reset/commit.
std::set<TemplateURLID> blacklisted_ids_;
// Timer used to delay calls to |UpdateLoader|.
base::OneShotTimer<InstantController> update_timer_;
// Timer used to delay showing loaders whose status isn't ok.
base::OneShotTimer<InstantController> show_timer_;
// Used by ScheduleForDestroy; see it for details.
ScopedRunnableMethodFactory<InstantController> destroy_factory_;
// URL last pased to ScheduleUpdate.
GURL scheduled_url_;
// List of InstantLoaders to destroy. See ScheduleForDestroy for details.
ScopedVector<InstantLoader> loaders_to_destroy_;
// The set of hosts that we don't use instant with. This is shared across all
// instances and only maintained for the current session.
static HostBlacklist* host_blacklist_;
DISALLOW_COPY_AND_ASSIGN(InstantController);
};
#endif // CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_