summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-14 21:38:30 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-14 21:38:30 +0000
commit03bb953da2a51fa35e7735ce711c1be6946312ea (patch)
treebd9fe31bd34036670ccc5247dcdba72cb9609400 /chrome/browser
parent037d1e192cfbad001946fe026d0460e636fa8e76 (diff)
downloadchromium_src-03bb953da2a51fa35e7735ce711c1be6946312ea.zip
chromium_src-03bb953da2a51fa35e7735ce711c1be6946312ea.tar.gz
chromium_src-03bb953da2a51fa35e7735ce711c1be6946312ea.tar.bz2
Bunch of match preview tweaks:
. Makes MatchPreview owned by Browser rather than each TabContents. . Makes MatchPreview dismiss when the omnibox closes. . Supports the ability to send script to the page rather than reloading on every keystroke. . Supports receiving results from the page that drives the suggest text in the omnbox. BUG=54833 TEST=none Review URL: http://codereview.chromium.org/3332022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59428 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.cc5
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.h7
-rw-r--r--chrome/browser/browser.cc56
-rw-r--r--chrome/browser/browser.h19
-rw-r--r--chrome/browser/browser_window.h6
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa.h2
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa.mm10
-rw-r--r--chrome/browser/cocoa/location_bar/location_bar_view_mac.h1
-rw-r--r--chrome/browser/cocoa/location_bar/location_bar_view_mac.mm5
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc10
-rw-r--r--chrome/browser/gtk/browser_window_gtk.h2
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc5
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.h1
-rw-r--r--chrome/browser/location_bar.h6
-rw-r--r--chrome/browser/search_engines/template_url.h6
-rw-r--r--chrome/browser/tab_contents/match_preview.cc408
-rw-r--r--chrome/browser/tab_contents/match_preview.h88
-rw-r--r--chrome/browser/tab_contents/match_preview_delegate.h32
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc4
-rw-r--r--chrome/browser/tab_contents/tab_contents.h6
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.cc3
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.h5
-rw-r--r--chrome/browser/views/app_launcher.cc1
-rw-r--r--chrome/browser/views/frame/browser_view.cc135
-rw-r--r--chrome/browser/views/frame/browser_view.h22
-rw-r--r--chrome/browser/views/frame/browser_view_layout.cc52
-rw-r--r--chrome/browser/views/frame/browser_view_layout.h24
-rw-r--r--chrome/browser/views/frame/contents_container.cc194
-rw-r--r--chrome/browser/views/frame/contents_container.h82
-rw-r--r--chrome/browser/views/location_bar/location_bar_view.cc135
-rw-r--r--chrome/browser/views/location_bar/location_bar_view.h17
-rw-r--r--chrome/browser/views/toolbar_view.cc4
-rw-r--r--chrome/browser/views/toolbar_view.h1
33 files changed, 1071 insertions, 283 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc
index 1162943..442ef5c 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit.cc
@@ -129,11 +129,10 @@ void AutocompleteEditModel::RestoreState(const State& state) {
}
}
-GURL AutocompleteEditModel::CurrentURL(PageTransition::Type* transition_type) {
+AutocompleteMatch AutocompleteEditModel::CurrentMatch() {
AutocompleteMatch match;
GetInfoForCurrentText(&match, NULL);
- *transition_type = match.transition;
- return match.destination_url;
+ return match;
}
bool AutocompleteEditModel::UpdatePermanentText(
diff --git a/chrome/browser/autocomplete/autocomplete_edit.h b/chrome/browser/autocomplete/autocomplete_edit.h
index 8376cb5..1454111 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.h
+++ b/chrome/browser/autocomplete/autocomplete_edit.h
@@ -134,10 +134,9 @@ class AutocompleteEditModel : public NotificationObserver {
// Restores local state from the saved |state|.
void RestoreState(const State& state);
- // Returns the url and transition type for the current text. If the user has
- // not edited the text this is the permanent url, otherwise it is the url the
- // user would navigate to if they accept the current edit.
- GURL CurrentURL(PageTransition::Type* transition_type);
+ // Returns the match for the current text. If the user has not edited the text
+ // this is the match corresponding to the permanent text.
+ AutocompleteMatch CurrentMatch();
// Called when the user wants to export the entire current text as a URL.
// Sets the url, and if known, the title and favicon.
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index a597915..1432000 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -254,6 +254,11 @@ Browser::Browser(Type type, Profile* profile)
if (profile_->GetProfileSyncService())
profile_->GetProfileSyncService()->AddObserver(this);
+
+ if (type == TYPE_NORMAL && MatchPreview::IsEnabled() &&
+ !profile->IsOffTheRecord()) {
+ match_preview_.reset(new MatchPreview(this));
+ }
}
Browser::~Browser() {
@@ -1263,6 +1268,13 @@ void Browser::OpenCurrentURL() {
LocationBar* location_bar = window_->GetLocationBar();
WindowOpenDisposition open_disposition =
location_bar->GetWindowOpenDisposition();
+ // TODO(sky): support other dispositions.
+ if (open_disposition == CURRENT_TAB && match_preview() &&
+ match_preview()->is_active()) {
+ match_preview()->CommitCurrentPreview();
+ return;
+ }
+
GURL url(WideToUTF8(location_bar->GetInputString()));
// Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
@@ -2500,6 +2512,9 @@ void Browser::TabDetachedAt(TabContents* contents, int index) {
}
void Browser::TabDeselectedAt(TabContents* contents, int index) {
+ if (match_preview())
+ match_preview()->DestroyPreviewContents();
+
// Save what the user's currently typing, so it can be restored when we
// switch back to this tab.
window_->GetLocationBar()->SaveStateToContents(contents);
@@ -3039,16 +3054,6 @@ void Browser::ContentTypeChanged(TabContents* source) {
UpdateZoomCommandsForTabState();
}
-void Browser::CommitMatchPreview(TabContents* source) {
- int index = tabstrip_model_.GetIndexOfTabContents(source);
- DCHECK_NE(-1, index);
- TabContents* preview_contents =
- source->match_preview()->ReleasePreviewContents();
- // TabStripModel takes ownership of preview_contents.
- tabstrip_model_.ReplaceTabContentsAt(
- index, preview_contents, TabStripModelObserver::REPLACE_MATCH_PREVIEW);
-}
-
///////////////////////////////////////////////////////////////////////////////
// Browser, SelectFileDialog::Listener implementation:
@@ -3218,6 +3223,37 @@ void Browser::OnStateChanged() {
}
///////////////////////////////////////////////////////////////////////////////
+// Browser, MatchPreviewDelegate implementation:
+
+void Browser::ShowMatchPreview() {
+ DCHECK(match_preview_->tab_contents() == GetSelectedTabContents());
+ window_->ShowMatchPreview();
+}
+
+void Browser::HideMatchPreview() {
+ if (match_preview_->tab_contents() == GetSelectedTabContents())
+ window_->HideMatchPreview();
+}
+
+void Browser::CommitMatchPreview() {
+ TabContents* tab_contents = match_preview_->tab_contents();
+ int index = tabstrip_model_.GetIndexOfTabContents(tab_contents);
+ DCHECK_NE(-1, index);
+ scoped_ptr<TabContents> preview_contents(
+ match_preview()->ReleasePreviewContents(true));
+ preview_contents->controller().CopyStateFromAndPrune(
+ tab_contents->controller());
+ // TabStripModel takes ownership of preview_contents.
+ tabstrip_model_.ReplaceTabContentsAt(
+ index, preview_contents.release(),
+ TabStripModelObserver::REPLACE_MATCH_PREVIEW);
+}
+
+void Browser::SetSuggestedText(const string16& text) {
+ window()->GetLocationBar()->SetSuggestedText(text);
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Browser, Command and state updating (private):
void Browser::InitCommandState() {
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index 3ff0647..eceaa39 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -14,6 +14,7 @@
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "base/task.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/debugger/devtools_toggle_action.h"
@@ -23,6 +24,7 @@
#include "chrome/browser/shell_dialogs.h"
#include "chrome/browser/sync/profile_sync_service_observer.h"
#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/tab_contents/match_preview_delegate.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/toolbar_model.h"
@@ -35,6 +37,7 @@
class BrowserWindow;
class Extension;
class FindBarController;
+class MatchPreview;
class PrefService;
class Profile;
class SessionStorageNamespace;
@@ -53,7 +56,8 @@ class Browser : public TabStripModelDelegate,
public NotificationObserver,
public SelectFileDialog::Listener,
public TabRestoreServiceObserver,
- public ProfileSyncServiceObserver {
+ public ProfileSyncServiceObserver,
+ public MatchPreviewDelegate {
public:
// If you change the values in this enum you'll need to update browser_proxy.
// TODO(sky): move into a common place that is referenced by both ui_tests
@@ -163,6 +167,10 @@ class Browser : public TabStripModelDelegate,
Profile* profile() const { return profile_; }
const std::vector<std::wstring>& user_data_dir_profiles() const;
+ // Returns the MatchPreview or NULL if there is no MatchPreview for this
+ // Browser.
+ MatchPreview* match_preview() const { return match_preview_.get(); }
+
#if defined(UNIT_TEST)
// Sets the BrowserWindow. This is intended for testing and generally not
// useful outside of testing. Use CreateBrowserWindow outside of testing, or
@@ -758,7 +766,6 @@ class Browser : public TabStripModelDelegate,
virtual void OnDidGetApplicationInfo(TabContents* tab_contents,
int32 page_id);
virtual void ContentTypeChanged(TabContents* source);
- virtual void CommitMatchPreview(TabContents* source);
// Overridden from SelectFileDialog::Listener:
virtual void FileSelected(const FilePath& path, int index, void* params);
@@ -771,6 +778,12 @@ class Browser : public TabStripModelDelegate,
// Overridden from ProfileSyncServiceObserver:
virtual void OnStateChanged();
+ // Overriden from MatchPreviewDelegate:
+ virtual void ShowMatchPreview();
+ virtual void HideMatchPreview();
+ virtual void CommitMatchPreview();
+ virtual void SetSuggestedText(const string16& text);
+
// Command and state updating ///////////////////////////////////////////////
// Initialize state for all browser commands.
@@ -1081,6 +1094,8 @@ class Browser : public TabStripModelDelegate,
// and we install ourselves as an observer.
TabRestoreService* tab_restore_service_;
+ scoped_ptr<MatchPreview> match_preview_;
+
DISALLOW_COPY_AND_ASSIGN(Browser);
};
diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h
index 98cd042..9009327 100644
--- a/chrome/browser/browser_window.h
+++ b/chrome/browser/browser_window.h
@@ -312,6 +312,12 @@ class BrowserWindow {
virtual void OpenTabpose() = 0;
#endif
+ // Invoked when the match preview's tab contents should be shown.
+ virtual void ShowMatchPreview() = 0;
+
+ // Invoked when the match preview's tab contents should be hidden.
+ virtual void HideMatchPreview() = 0;
+
// Construct a BrowserWindow implementation for the specified |browser|.
static BrowserWindow* CreateBrowserWindow(Browser* browser);
diff --git a/chrome/browser/cocoa/browser_window_cocoa.h b/chrome/browser/cocoa/browser_window_cocoa.h
index 10b9fd3..226e573 100644
--- a/chrome/browser/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/cocoa/browser_window_cocoa.h
@@ -106,6 +106,8 @@ class BrowserWindowCocoa : public BrowserWindow,
virtual void Paste();
virtual void ToggleTabStripMode();
virtual void OpenTabpose();
+ virtual void ShowMatchPreview();
+ virtual void HideMatchPreview();
// Overridden from NotificationObserver
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm
index fa9d6c6..f889a3c 100644
--- a/chrome/browser/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/cocoa/browser_window_cocoa.mm
@@ -564,6 +564,16 @@ void BrowserWindowCocoa::OpenTabpose() {
[controller_ openTabpose];
}
+void BrowserWindowCocoa::ShowMatchPreview() {
+ // TODO: implement me
+ NOTIMPLEMENTED();
+}
+
+void BrowserWindowCocoa::HideMatchPreview() {
+ // TODO: implement me
+ NOTIMPLEMENTED();
+}
+
void BrowserWindowCocoa::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
diff --git a/chrome/browser/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/cocoa/location_bar/location_bar_view_mac.h
index 6a7a598..0ec9058 100644
--- a/chrome/browser/cocoa/location_bar/location_bar_view_mac.h
+++ b/chrome/browser/cocoa/location_bar/location_bar_view_mac.h
@@ -54,6 +54,7 @@ class LocationBarViewMac : public AutocompleteEditController,
// Overridden from LocationBar:
virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type);
+ virtual void SetSuggestedText(const string16& text);
virtual std::wstring GetInputString() const;
virtual WindowOpenDisposition GetWindowOpenDisposition() const;
virtual PageTransition::Type GetPageTransition() const;
diff --git a/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm
index 9bc4d1d..d8b8b80 100644
--- a/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm
+++ b/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm
@@ -124,6 +124,11 @@ std::wstring LocationBarViewMac::GetInputString() const {
return location_input_;
}
+void LocationBarViewMac::SetSuggestedText(const string16& text) {
+ // TODO: implement me.
+ NOTIMPLEMENTED();
+}
+
WindowOpenDisposition LocationBarViewMac::GetWindowOpenDisposition() const {
return disposition_;
}
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index da1a13d..1c8418f 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -1129,6 +1129,16 @@ void BrowserWindowGtk::Paste() {
DoCutCopyPaste(this, &RenderViewHost::Paste, "paste-clipboard");
}
+void BrowserWindowGtk::ShowMatchPreview() {
+ // TODO: implement me
+ NOTIMPLEMENTED();
+}
+
+void BrowserWindowGtk::HideMatchPreview() {
+ // TODO: implement me
+ NOTIMPLEMENTED();
+}
+
void BrowserWindowGtk::ConfirmBrowserCloseWithPendingDownloads() {
new DownloadInProgressDialogGtk(browser());
}
diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h
index 44dedb4..f80be5e 100644
--- a/chrome/browser/gtk/browser_window_gtk.h
+++ b/chrome/browser/gtk/browser_window_gtk.h
@@ -123,6 +123,8 @@ class BrowserWindowGtk : public BrowserWindow,
virtual void Copy();
virtual void Paste();
virtual void ToggleTabStripMode() {}
+ virtual void ShowMatchPreview();
+ virtual void HideMatchPreview();
// Overridden from NotificationObserver:
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc
index 705be84..3d3cefd 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/gtk/location_bar_view_gtk.cc
@@ -544,6 +544,11 @@ void LocationBarViewGtk::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) {
MessageLoop::current()->PostTask(FROM_HERE, task);
}
+void LocationBarViewGtk::SetSuggestedText(const string16& text) {
+ // TODO: implement me.
+ NOTIMPLEMENTED();
+}
+
std::wstring LocationBarViewGtk::GetInputString() const {
return location_input_;
}
diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h
index c0fef25..8c820d2 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.h
+++ b/chrome/browser/gtk/location_bar_view_gtk.h
@@ -101,6 +101,7 @@ class LocationBarViewGtk : public AutocompleteEditController,
// Implement the LocationBar interface.
virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type);
+ virtual void SetSuggestedText(const string16& text);
virtual std::wstring GetInputString() const;
virtual WindowOpenDisposition GetWindowOpenDisposition() const;
virtual PageTransition::Type GetPageTransition() const;
diff --git a/chrome/browser/location_bar.h b/chrome/browser/location_bar.h
index d16bd8f..b6a6d0d 100644
--- a/chrome/browser/location_bar.h
+++ b/chrome/browser/location_bar.h
@@ -14,6 +14,7 @@
#include <string>
+#include "base/string16.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/common/page_transition_types.h"
#include "webkit/glue/window_open_disposition.h"
@@ -28,12 +29,9 @@ class LocationBar {
// Shows the first run information bubble anchored to the location bar.
virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type) = 0;
- // TODO: port
-#if defined(TOOLKIT_VIEWS)
// Sets the suggested text to show in the omnibox. This is shown in addition
// to the current text of the omnibox.
- virtual void SetSuggestedText(const std::wstring& text) = 0;
-#endif
+ virtual void SetSuggestedText(const string16& text) = 0;
// Returns the string of text entered in the location bar.
virtual std::wstring GetInputString() const = 0;
diff --git a/chrome/browser/search_engines/template_url.h b/chrome/browser/search_engines/template_url.h
index 42eb0bf..ceaa0ecd2 100644
--- a/chrome/browser/search_engines/template_url.h
+++ b/chrome/browser/search_engines/template_url.h
@@ -277,7 +277,7 @@ class TemplateURL {
// Generates a favicon URL from the specified url.
static GURL GenerateFaviconURL(const GURL& url);
- // Returns true if |true| is non-null and has a search URL that supports
+ // Returns true if |turl| is non-null and has a search URL that supports
// replacement.
static bool SupportsReplacement(const TemplateURL* turl);
@@ -297,6 +297,10 @@ class TemplateURL {
}
const std::wstring& short_name() const { return short_name_; }
+ // Returns true if this search engine supports showing instant results.
+ // TODO(sky): make this real.
+ bool supports_instant() const { return false; }
+
// An accessor for the short_name, but adjusted so it can be appropriately
// displayed even if it is LTR and the UI is RTL.
std::wstring AdjustedShortNameForLocaleDirection() const;
diff --git a/chrome/browser/tab_contents/match_preview.cc b/chrome/browser/tab_contents/match_preview.cc
index 709a582..d167ceb 100644
--- a/chrome/browser/tab_contents/match_preview.cc
+++ b/chrome/browser/tab_contents/match_preview.cc
@@ -7,20 +7,204 @@
#include <algorithm>
#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/favicon_service.h"
+#include "chrome/browser/history/history_marshaling.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/tab_contents/match_preview_delegate.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/page_transition_types.h"
+#include "chrome/common/render_messages.h"
#include "chrome/common/renderer_preferences.h"
+#include "gfx/codec/png_codec.h"
#include "ipc/ipc_message.h"
+namespace {
+
+const char kUserInputScript[] =
+ "if (window.chrome.userInput) window.chrome.userInput(\"$1\");";
+
+// Sends the user input script to |tab_contents|. |text| is the text the user
+// input into the omnibox.
+void SendUserInputScript(TabContents* tab_contents,
+ const string16& text,
+ bool done) {
+ // TODO: support done.
+ string16 escaped_text(text);
+ ReplaceSubstringsAfterOffset(&escaped_text, 0L, ASCIIToUTF16("\""),
+ ASCIIToUTF16("\\\""));
+ string16 script = ReplaceStringPlaceholders(ASCIIToUTF16(kUserInputScript),
+ escaped_text, NULL);
+ tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
+ std::wstring(),
+ UTF16ToWide(script));
+}
+
+} // namespace
+
+// FrameLoadObserver is responsible for waiting for the TabContents to finish
+// loading and when done sending the necessary script down to the page.
+class MatchPreview::FrameLoadObserver : public NotificationObserver {
+ public:
+ FrameLoadObserver(MatchPreview* match_preview, const string16& text)
+ : match_preview_(match_preview),
+ tab_contents_(match_preview->preview_contents()),
+ unique_id_(tab_contents_->controller().pending_entry()->unique_id()),
+ text_(text),
+ send_done_(false) {
+ registrar_.Add(this, NotificationType::LOAD_COMPLETED_MAIN_FRAME,
+ Source<TabContents>(tab_contents_));
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents_));
+ }
+
+ // Sets the text to send to the page.
+ void set_text(const string16& text) { text_ = text; }
+
+ // Invoked when the MatchPreview releases ownership of the TabContents and
+ // the page hasn't finished loading.
+ void DetachFromPreview() {
+ match_preview_ = NULL;
+ send_done_ = true;
+ }
+
+ // NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::LOAD_COMPLETED_MAIN_FRAME: {
+ int page_id = *(Details<int>(details).ptr());
+ NavigationEntry* active_entry =
+ tab_contents_->controller().GetActiveEntry();
+ if (!active_entry || active_entry->page_id() != page_id ||
+ active_entry->unique_id() != unique_id_) {
+ return;
+ }
+
+ SendUserInputScript(tab_contents_, text_, send_done_);
+
+ if (match_preview_)
+ match_preview_->PageFinishedLoading();
+
+ delete this;
+ return;
+ }
+
+ case NotificationType::TAB_CONTENTS_DESTROYED:
+ delete this;
+ return;
+
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ private:
+ // MatchPreview that created us.
+ MatchPreview* match_preview_;
+
+ // The TabContents we're listening for changes on.
+ TabContents* tab_contents_;
+
+ // unique_id of the NavigationEntry we're waiting on.
+ const int unique_id_;
+
+ // Text to send down to the page.
+ string16 text_;
+
+ // Passed to SendScript.
+ bool send_done_;
+
+ // Registers and unregisters us for notifications.
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameLoadObserver);
+};
+
+// PaintObserver implementation. When the RenderWidgetHost paints itself this
+// notifies MatchPreview, which makes the TabContents active.
+class MatchPreview::PaintObserverImpl : public RenderWidgetHost::PaintObserver {
+ public:
+ explicit PaintObserverImpl(MatchPreview* preview)
+ : match_preview_(preview) {
+ }
+
+ virtual void RenderWidgetHostWillPaint(RenderWidgetHost* rwh) {
+ }
+
+ virtual void RenderWidgetHostDidPaint(RenderWidgetHost* rwh) {
+ match_preview_->PreviewDidPaint();
+ rwh->set_paint_observer(NULL);
+ // WARNING: we've been deleted.
+ }
+
+ private:
+ MatchPreview* match_preview_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaintObserverImpl);
+};
+
class MatchPreview::TabContentsDelegateImpl : public TabContentsDelegate {
public:
explicit TabContentsDelegateImpl(MatchPreview* match_preview)
- : match_preview_(match_preview) {
+ : match_preview_(match_preview),
+ installed_paint_observer_(false),
+ waiting_for_new_page_(true) {
+ }
+
+ // Invoked prior to loading a new URL.
+ void PrepareForNewLoad() {
+ waiting_for_new_page_ = true;
+ add_page_vector_.clear();
+ }
+
+ // Invoked when removed as the delegate. Gives a chance to do any necessary
+ // cleanup.
+ void Reset() {
+ installed_paint_observer_ = false;
+ }
+
+ // Commits the currently buffered history.
+ void CommitHistory() {
+ TabContents* tab = match_preview_->preview_contents();
+ if (tab->profile()->IsOffTheRecord())
+ return;
+
+ for (size_t i = 0; i < add_page_vector_.size(); ++i)
+ tab->UpdateHistoryForNavigation(add_page_vector_[i].get());
+
+ NavigationEntry* active_entry = tab->controller().GetActiveEntry();
+ DCHECK(active_entry);
+ tab->UpdateHistoryPageTitle(*active_entry);
+
+ FaviconService* favicon_service =
+ tab->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS);
+
+ if (favicon_service && active_entry->favicon().is_valid() &&
+ !active_entry->favicon().bitmap().empty()) {
+ std::vector<unsigned char> image_data;
+ gfx::PNGCodec::EncodeBGRASkBitmap(active_entry->favicon().bitmap(), false,
+ &image_data);
+ favicon_service->SetFavicon(active_entry->url(),
+ active_entry->favicon().url(),
+ image_data);
+ }
}
virtual void OpenURLFromTab(TabContents* source,
@@ -28,14 +212,24 @@ class MatchPreview::TabContentsDelegateImpl : public TabContentsDelegate {
WindowOpenDisposition disposition,
PageTransition::Type transition) {}
virtual void NavigationStateChanged(const TabContents* source,
- unsigned changed_flags) {}
+ unsigned changed_flags) {
+ if (!installed_paint_observer_ && source->controller().entry_count()) {
+ // The load has been committed. Install an observer that waits for the
+ // first paint then makes the preview active. We wait for the load to be
+ // committed before waiting on paint as there is always an initial paint
+ // when a new renderer is created from the resize so that if we showed the
+ // preview after the first paint we would end up with a white rect.
+ installed_paint_observer_ = true;
+ source->GetRenderWidgetHostView()->GetRenderWidgetHost()->
+ set_paint_observer(new PaintObserverImpl(match_preview_));
+ }
+ }
virtual void AddNewContents(TabContents* source,
TabContents* new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_pos,
bool user_gesture) {}
virtual void ActivateContents(TabContents* contents) {
- match_preview_->CommitCurrentPreview();
}
virtual void DeactivateContents(TabContents* contents) {}
virtual void LoadingStateChanged(TabContents* source) {}
@@ -59,9 +253,7 @@ class MatchPreview::TabContentsDelegateImpl : public TabContentsDelegate {
virtual void ConvertContentsToApplication(TabContents* source) {}
virtual bool CanReloadContents(TabContents* source) const { return true; }
virtual gfx::Rect GetRootWindowResizerRect() const {
- return match_preview_->host_->delegate() ?
- match_preview_->host_->delegate()->GetRootWindowResizerRect() :
- gfx::Rect();
+ return gfx::Rect();
}
virtual void ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
gfx::NativeWindow parent_window) {}
@@ -82,7 +274,6 @@ class MatchPreview::TabContentsDelegateImpl : public TabContentsDelegate {
virtual bool TakeFocus(bool reverse) { return false; }
virtual void SetTabContentBlocked(TabContents* contents, bool blocked) {}
virtual void TabContentsFocused(TabContents* tab_content) {
- match_preview_->CommitCurrentPreview();
}
virtual int GetExtraRenderViewHeight() const { return 0; }
virtual bool CanDownload(int request_id) { return false; }
@@ -108,16 +299,22 @@ class MatchPreview::TabContentsDelegateImpl : public TabContentsDelegate {
virtual void ShowContentSettingsWindow(ContentSettingsType content_type) {}
virtual void ShowCollectedCookiesDialog(TabContents* tab_contents) {}
virtual bool OnGoToEntryOffset(int offset) { return false; }
- virtual bool ShouldAddNavigationToHistory(
+ virtual bool ShouldAddNavigationsToHistory(
const history::HistoryAddPageArgs& add_page_args,
NavigationType::Type navigation_type) {
+ if (waiting_for_new_page_ && navigation_type == NavigationType::NEW_PAGE)
+ waiting_for_new_page_ = false;
+
+ if (!waiting_for_new_page_) {
+ add_page_vector_.push_back(
+ scoped_refptr<history::HistoryAddPageArgs>(add_page_args.Clone()));
+ }
return false;
}
virtual void OnDidGetApplicationInfo(TabContents* tab_contents,
int32 page_id) {}
virtual gfx::NativeWindow GetFrameNativeWindow() {
- return match_preview_->host_->delegate() ?
- match_preview_->host_->delegate()->GetFrameNativeWindow() : NULL;
+ return NULL;
}
virtual void TabContentsCreated(TabContents* new_contents) {}
virtual bool infobars_enabled() { return false; }
@@ -125,21 +322,37 @@ class MatchPreview::TabContentsDelegateImpl : public TabContentsDelegate {
virtual void UpdatePreferredSize(const gfx::Size& pref_size) {}
virtual void ContentTypeChanged(TabContents* source) {}
+ virtual void OnSetSuggestResult(int32 page_id, const std::string& result) {
+ TabContents* source = match_preview_->preview_contents();
+ // TODO: only allow for default search provider.
+ if (source->controller().GetActiveEntry() &&
+ page_id == source->controller().GetActiveEntry()->page_id()) {
+ match_preview_->SetCompleteSuggestedText(UTF8ToUTF16(result));
+ }
+ }
+
private:
+ typedef std::vector<scoped_refptr<history::HistoryAddPageArgs> >
+ AddPageVector;
+
MatchPreview* match_preview_;
- DISALLOW_COPY_AND_ASSIGN(TabContentsDelegateImpl);
-};
+ // Has the paint observer been installed? See comment in
+ // NavigationStateChanged for details on this.
+ bool installed_paint_observer_;
-MatchPreview::MatchPreview(TabContents* host) : host_(host) {
- delegate_.reset(new TabContentsDelegateImpl(this));
-}
+ // Used to cache data that needs to be added to history. Normally entries are
+ // added to history as the user types, but for match preview we only want to
+ // add the items to history if the user commits the match preview. So, we
+ // cache them here and if committed then add the items to history.
+ AddPageVector add_page_vector_;
-MatchPreview::~MatchPreview() {
- // Delete the TabContents before the delegate as the TabContents holds a
- // reference to the delegate.
- preview_contents_.reset(NULL);
-}
+ // Are we we waiting for a NavigationType of NEW_PAGE? If we're waiting for
+ // NEW_PAGE navigation we don't add history items to add_page_vector_.
+ bool waiting_for_new_page_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabContentsDelegateImpl);
+};
// static
bool MatchPreview::IsEnabled() {
@@ -153,44 +366,163 @@ bool MatchPreview::IsEnabled() {
return enabled;
}
-void MatchPreview::Update(const GURL& url) {
- if (url_ == url)
+MatchPreview::MatchPreview(MatchPreviewDelegate* delegate)
+ : delegate_(delegate),
+ tab_contents_(NULL),
+ is_active_(false),
+ template_url_id_(0) {
+ preview_tab_contents_delegate_.reset(new TabContentsDelegateImpl(this));
+}
+
+MatchPreview::~MatchPreview() {
+ // Delete the TabContents before the delegate as the TabContents holds a
+ // reference to the delegate.
+ preview_contents_.reset(NULL);
+}
+
+void MatchPreview::Update(TabContents* tab_contents,
+ const AutocompleteMatch& match,
+ const string16& user_text,
+ string16* suggested_text) {
+ if (tab_contents != tab_contents_)
+ DestroyPreviewContents();
+
+ tab_contents_ = tab_contents;
+
+ if (url_ == match.destination_url)
return;
- url_ = url;
+ url_ = match.destination_url;
if (url_.is_empty() || !url_.is_valid()) {
DestroyPreviewContents();
return;
}
- if (!preview_contents_.get()) {
+ user_text_ = user_text;
+
+ if (preview_contents_.get() == NULL) {
preview_contents_.reset(
- new TabContents(host_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL));
- preview_contents_->set_delegate(delegate_.get());
- NotificationService::current()->Notify(
- NotificationType::MATCH_PREVIEW_TAB_CONTENTS_CREATED,
- Source<TabContents>(host_),
- NotificationService::NoDetails());
+ new TabContents(tab_contents_->profile(), NULL, MSG_ROUTING_NONE,
+ NULL, NULL));
+ // Propagate the max page id. That way if we end up merging the two
+ // NavigationControllers (which happens if we commit) none of the page ids
+ // will overlap.
+ int32 max_page_id = tab_contents_->GetMaxPageID();
+ if (max_page_id != -1)
+ preview_contents_->controller().set_max_restored_page_id(max_page_id + 1);
+
+ preview_contents_->set_delegate(preview_tab_contents_delegate_.get());
+
+ gfx::Rect tab_bounds;
+ tab_contents_->view()->GetContainerBounds(&tab_bounds);
+ preview_contents_->view()->SizeContents(tab_bounds.size());
+
+ preview_contents_->ShowContents();
}
+ preview_tab_contents_delegate_->PrepareForNewLoad();
- // TODO: figure out transition type.
- preview_contents_->controller().LoadURL(url, GURL(),
- PageTransition::GENERATED);
+ const TemplateURL* template_url = match.template_url;
+ if (match.type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED ||
+ match.type == AutocompleteMatch::SEARCH_HISTORY ||
+ match.type == AutocompleteMatch::SEARCH_SUGGEST) {
+ TemplateURLModel* model = tab_contents->profile()->GetTemplateURLModel();
+ template_url = model ? model->GetDefaultSearchProvider() : NULL;
+ }
+ TemplateURLID template_url_id = template_url ? template_url->id() : 0;
+
+ if (template_url && template_url->supports_instant() &&
+ TemplateURL::SupportsReplacement(template_url)) {
+ if (template_url_id == template_url_id_) {
+ if (frame_load_observer_.get()) {
+ // The page hasn't loaded yet. We'll send the script down when it does.
+ frame_load_observer_->set_text(user_text_);
+ return;
+ }
+ SendUserInputScript(preview_contents_.get(), user_text_, false);
+ if (complete_suggested_text_.size() > user_text_.size() &&
+ !complete_suggested_text_.compare(0, user_text_.size(), user_text_)) {
+ *suggested_text = complete_suggested_text_.substr(user_text_.size());
+ }
+ } else {
+ // TODO: should we use a different url for instant?
+ GURL url = GURL(template_url->url()->ReplaceSearchTerms(
+ *template_url, std::wstring(),
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()));
+ // user_text_ is sent once the page finishes loading by FrameLoadObserver.
+ preview_contents_->controller().LoadURL(url, GURL(), match.transition);
+ frame_load_observer_.reset(new FrameLoadObserver(this, user_text_));
+ }
+ } else {
+ frame_load_observer_.reset(NULL);
+ preview_contents_->controller().LoadURL(url_, GURL(), match.transition);
+ }
+
+ template_url_id_ = template_url_id;
}
void MatchPreview::DestroyPreviewContents() {
- url_ = GURL();
- preview_contents_.reset(NULL);
+ delegate_->HideMatchPreview();
+ delete ReleasePreviewContents(false);
}
void MatchPreview::CommitCurrentPreview() {
DCHECK(preview_contents_.get());
- if (host_->delegate())
- host_->delegate()->CommitMatchPreview(host_);
+ delegate_->CommitMatchPreview();
}
-TabContents* MatchPreview::ReleasePreviewContents() {
+TabContents* MatchPreview::ReleasePreviewContents(bool commit_history) {
+ template_url_id_ = 0;
url_ = GURL();
+ user_text_.clear();
+ complete_suggested_text_.clear();
+ if (frame_load_observer_.get()) {
+ frame_load_observer_->DetachFromPreview();
+ // FrameLoadObserver will delete itself either when the TabContents is
+ // deleted, or when the page finishes loading.
+ FrameLoadObserver* unused ALLOW_UNUSED = frame_load_observer_.release();
+ }
+ if (preview_contents_.get()) {
+ if (commit_history)
+ preview_tab_contents_delegate_->CommitHistory();
+ // Destroy the paint observer.
+ if (preview_contents_->GetRenderWidgetHostView()) {
+ // RenderWidgetHostView may be null during shutdown.
+ preview_contents_->GetRenderWidgetHostView()->GetRenderWidgetHost()->
+ set_paint_observer(NULL);
+ }
+ preview_contents_->set_delegate(NULL);
+ preview_tab_contents_delegate_->Reset();
+ is_active_ = false;
+ }
return preview_contents_.release();
}
+
+void MatchPreview::SetCompleteSuggestedText(
+ const string16& complete_suggested_text) {
+ if (complete_suggested_text == complete_suggested_text_)
+ return;
+
+ if (user_text_.compare(0, user_text_.size(), complete_suggested_text,
+ 0, user_text_.size())) {
+ // The user text no longer contains the suggested text, ignore it.
+ complete_suggested_text_.clear();
+ delegate_->SetSuggestedText(string16());
+ return;
+ }
+
+ complete_suggested_text_ = complete_suggested_text;
+ delegate_->SetSuggestedText(
+ complete_suggested_text_.substr(user_text_.size()));
+}
+
+void MatchPreview::PreviewDidPaint() {
+ DCHECK(!is_active_);
+ is_active_ = true;
+ delegate_->ShowMatchPreview();
+}
+
+void MatchPreview::PageFinishedLoading() {
+ // FrameLoadObserver deletes itself after this call.
+ FrameLoadObserver* unused ALLOW_UNUSED = frame_load_observer_.release();
+}
diff --git a/chrome/browser/tab_contents/match_preview.h b/chrome/browser/tab_contents/match_preview.h
index cc6605b..f699f89 100644
--- a/chrome/browser/tab_contents/match_preview.h
+++ b/chrome/browser/tab_contents/match_preview.h
@@ -4,31 +4,31 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_MATCH_PREVIEW_H_
#define CHROME_BROWSER_TAB_CONTENTS_MATCH_PREVIEW_H_
+#pragma once
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "base/timer.h"
+#include "chrome/browser/search_engines/template_url_id.h"
+#include "chrome/common/page_transition_types.h"
#include "googleurl/src/gurl.h"
+struct AutocompleteMatch;
+class MatchPreviewDelegate;
class TabContents;
// MatchPreview maintains a TabContents that is intended to give a preview of
-// a URL. MatchPreview is owned by TabContents.
-//
-// As the user types in the omnibox the LocationBar updates MatchPreview by
-// way of 'Update'. If the user does a gesture on the preview, say clicks a
-// link, the TabContentsDelegate of the hosting TabContents is notified with
-// CommitMatchPreview and the TabContents maintained by MatchPreview replaces
-// the current TabContents in the TabStripModel.
+// a URL. MatchPreview is owned by Browser.
//
// At any time the TabContents maintained by MatchPreview may be destroyed by
-// way of 'DestroyPreviewContents'. Consumers of MatchPreview can detect the
-// preview TabContents was destroyed by observing TAB_CONTENTS_DESTROYED.
-//
-// Consumers of MatchPreview can detect a new TabContents was created by
-// MatchPreview by listening for MATCH_PREVIEW_TAB_CONTENTS_CREATED.
+// way of |DestroyPreviewContents|, which results in |HideMatchPreview| being
+// invoked on the delegate. Similarly the preview may be committed at any time
+// by invoking |CommitCurrentPreview|, which results in |CommitMatchPreview|
+// being invoked on the delegate.
class MatchPreview {
public:
- explicit MatchPreview(TabContents* host);
+ explicit MatchPreview(MatchPreviewDelegate* delegate);
~MatchPreview();
// Is MatchPreview enabled?
@@ -38,7 +38,10 @@ class MatchPreview {
// 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.
- void Update(const GURL& url);
+ void Update(TabContents* tab_contents,
+ const AutocompleteMatch& match,
+ const string16& user_text,
+ string16* suggested_text);
// Destroys the preview TabContents. Does nothing if the preview TabContents
// has not been created.
@@ -49,31 +52,70 @@ class MatchPreview {
void CommitCurrentPreview();
// Releases the preview TabContents passing ownership to the caller. This is
- // intended to be called when the preview TabContents is committed.
- TabContents* ReleasePreviewContents();
+ // intended to be called when the preview TabContents is committed. This does
+ // not notify the delegate.
+ TabContents* ReleasePreviewContents(bool commit_history);
- // The TabContents we're maintaining the preview for.
- TabContents* host() { return host_; }
+ // TabContents the match is being shown for.
+ TabContents* tab_contents() const { return tab_contents_; }
// The preview TabContents; may be null.
- TabContents* preview_contents() { return preview_contents_.get(); }
+ TabContents* preview_contents() const { return preview_contents_.get(); }
+
+ // Returns true if the preview TabContents is active. In some situations this
+ // may return false yet preview_contents() returns non-NULL.
+ bool is_active() const { return is_active_; }
+
+ const GURL& url() const { return url_; }
private:
+ class FrameLoadObserver;
+ class PaintObserverImpl;
class TabContentsDelegateImpl;
+ // Invoked when the page wants to update the suggested text. If |user_text_|
+ // starts with |suggested_text|, then the delegate is notified of the change,
+ // which results in updating the omnibox.
+ void SetCompleteSuggestedText(const string16& suggested_text);
+
+ // Invoked when the preview paints. This notifies the delegate the preview is
+ // ready to be shown.
+ void PreviewDidPaint();
+
+ // Invoked once the page has finished loading and the script has been sent.
+ void PageFinishedLoading();
+
+ MatchPreviewDelegate* delegate_;
+
+ // The TabContents last passed to |Update|.
+ TabContents* tab_contents_;
+
// The url we're displaying.
GURL url_;
- // The TabContents we're providing the preview for.
- TabContents* host_;
-
// Delegate of the preview TabContents. Used to detect when the user does some
// gesture on the TabContents and the preview needs to be activated.
- scoped_ptr<TabContentsDelegateImpl> delegate_;
+ scoped_ptr<TabContentsDelegateImpl> preview_tab_contents_delegate_;
// The preview TabContents; may be null.
scoped_ptr<TabContents> preview_contents_;
+ // Has notification been sent out that the preview TabContents is ready to be
+ // shown?
+ bool is_active_;
+
+ // The text the user typed in the omnibox.
+ string16 user_text_;
+
+ // The latest suggestion from the page.
+ string16 complete_suggested_text_;
+
+ // If we're showing instant results this is the ID of the TemplateURL driving
+ // the results. A value of 0 means there is no TemplateURL.
+ TemplateURLID template_url_id_;
+
+ scoped_ptr<FrameLoadObserver> frame_load_observer_;
+
DISALLOW_COPY_AND_ASSIGN(MatchPreview);
};
diff --git a/chrome/browser/tab_contents/match_preview_delegate.h b/chrome/browser/tab_contents/match_preview_delegate.h
new file mode 100644
index 0000000..9d12cf8
--- /dev/null
+++ b/chrome/browser/tab_contents/match_preview_delegate.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 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_TAB_CONTENTS_MATCH_PREVIEW_DELEGATE_H_
+#define CHROME_BROWSER_TAB_CONTENTS_MATCH_PREVIEW_DELEGATE_H_
+#pragma once
+
+#include "base/string16.h"
+
+// MatchPreview's delegate. Normally the Browser implements this. See
+// MatchPreview for details.
+class MatchPreviewDelegate {
+ public:
+ // Invoked when the preview TabContents should be shown.
+ virtual void ShowMatchPreview() = 0;
+
+ // Invoked when the preview TabContents should be hidden.
+ virtual void HideMatchPreview() = 0;
+
+ // Invoked when the user does something that should result in the preview
+ // TabContents becoming the active TabContents.
+ virtual void CommitMatchPreview() = 0;
+
+ // Invoked when the suggested text is to change to |text|.
+ virtual void SetSuggestedText(const string16& text) = 0;
+
+ protected:
+ virtual ~MatchPreviewDelegate() {}
+};
+
+#endif // CHROME_BROWSER_TAB_CONTENTS_MATCH_PREVIEW_DELEGATE_H_
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index b5b4d49..eb3826d 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -77,7 +77,6 @@
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
-#include "chrome/browser/tab_contents/match_preview.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/provisional_load_details.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
@@ -434,9 +433,6 @@ TabContents::TabContents(Profile* profile,
// Set-up the showing of the omnibox search infobar if applicable.
if (OmniboxSearchHint::IsEnabled(profile))
omnibox_search_hint_.reset(new OmniboxSearchHint(this));
-
- if (MatchPreview::IsEnabled())
- match_preview_.reset(new MatchPreview(this));
}
TabContents::~TabContents() {
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index 39596f3..63759b4 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -72,7 +72,6 @@ class Extension;
class FileSelectHelper;
class InfoBarDelegate;
class LoadNotificationDetails;
-class MatchPreview;
class OmniboxSearchHint;
class PasswordManager;
class PluginInstaller;
@@ -168,9 +167,6 @@ class TabContents : public PageNavigator,
// Returns the TabContentsSSLHelper, creating it if necessary.
TabContentsSSLHelper* GetSSLHelper();
- // Returns the MatchPreview. Returns NULL if MatchPreview is not enabled.
- MatchPreview* match_preview() { return match_preview_.get(); }
-
// Returns the SavePackage which manages the page saving job. May be NULL.
SavePackage* save_package() const { return save_package_.get(); }
@@ -1277,8 +1273,6 @@ class TabContents : public PageNavigator,
// See description in RenderViewHostDelegate::SetDisplayingPDFContent.
bool displaying_pdf_content_;
- scoped_ptr<MatchPreview> match_preview_;
-
// ---------------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN(TabContents);
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.cc b/chrome/browser/tab_contents/tab_contents_delegate.cc
index 615a438..7e07ed6 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.cc
+++ b/chrome/browser/tab_contents/tab_contents_delegate.cc
@@ -165,9 +165,6 @@ void TabContentsDelegate::UpdatePreferredSize(const gfx::Size& pref_size) {
void TabContentsDelegate::ContentTypeChanged(TabContents* source) {
}
-void TabContentsDelegate::CommitMatchPreview(TabContents* source) {
-}
-
void TabContentsDelegate::OnSetSuggestResult(int32 page_id,
const std::string& result) {
}
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h
index 56b4c9f..6baa57c 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.h
+++ b/chrome/browser/tab_contents/tab_contents_delegate.h
@@ -285,11 +285,6 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
// PDF using the internal PDF plugin.
virtual void ContentTypeChanged(TabContents* source);
- // Sent when the user does a gesture that results in committing the match
- // preview. The delegate should replace |source| with the |source|'s match
- // preview TabContents.
- virtual void CommitMatchPreview(TabContents* source);
-
// Notifies the delegate that the page has a suggest result.
virtual void OnSetSuggestResult(int32 page_id, const std::string& result);
diff --git a/chrome/browser/views/app_launcher.cc b/chrome/browser/views/app_launcher.cc
index 3f8bdbf..880b085 100644
--- a/chrome/browser/views/app_launcher.cc
+++ b/chrome/browser/views/app_launcher.cc
@@ -85,6 +85,7 @@ class InfoBubbleContentsView : public views::View,
// WARNING: this is not the TabContents of the bubble! Use
// GetBubbleTabContents() to get the bubble's TabContents.
virtual TabContents* GetTabContents();
+ virtual MatchPreview* GetMatchPreview() { return NULL; }
virtual void OnInputInProgress(bool in_progress) {}
// CommandUpdater::CommandUpdaterDelegate implementation:
diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc
index c0ba2cc..29330d1 100644
--- a/chrome/browser/views/frame/browser_view.cc
+++ b/chrome/browser/views/frame/browser_view.cc
@@ -43,6 +43,7 @@
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/browser/views/download_shelf_view.h"
#include "chrome/browser/views/frame/browser_view_layout.h"
+#include "chrome/browser/views/frame/contents_container.h"
#include "chrome/browser/views/fullscreen_exit_bubble.h"
#include "chrome/browser/views/status_bubble_views.h"
#include "chrome/browser/views/tab_contents/tab_contents_container.h"
@@ -135,75 +136,6 @@ static gfx::NativeWindow GetNormalBrowserWindowForBrowser(Browser* browser,
}
#endif // defined(OS_CHROMEOS)
-// ContentsContainer is responsible for managing the TabContents views.
-// ContentsContainer has up to two children: one for the currently active
-// TabContents and one for the match preview TabContents.
-class BrowserView::ContentsContainer : public views::View {
- public:
- ContentsContainer(BrowserView* browser_view, views::View* active)
- : browser_view_(browser_view),
- active_(active),
- preview_(NULL) {
- AddChildView(active_);
- }
-
- // Makes the preview view the active view and nulls out the old active view.
- // It's assumed the caller will delete or remove the old active view
- // separately.
- void MakePreviewContentsActiveContents() {
- active_ = preview_;
- preview_ = NULL;
- Layout();
- }
-
- // Sets the preview view. This does not delete the old.
- void SetPreview(views::View* preview) {
- if (preview == preview_)
- return;
-
- if (preview_)
- RemoveChildView(preview_);
- preview_ = preview;
- if (preview_)
- AddChildView(preview_);
-
- Layout();
- }
-
- virtual void Layout() {
- // The active view always gets the full bounds.
- active_->SetBounds(0, 0, width(), height());
-
- if (preview_) {
- // The preview view gets the full width and is positioned beneath the
- // bottom of the autocompleted popup.
- int max_autocomplete_y = browser_view_->toolbar()->location_bar()->
- location_entry()->model()->popup_model()->view()->GetMaxYCoordinate();
- gfx::Point screen_origin;
- views::View::ConvertPointToScreen(this, &screen_origin);
- DCHECK_GT(max_autocomplete_y, screen_origin.y());
- int preview_origin = max_autocomplete_y - screen_origin.y();
- if (preview_origin < height()) {
- preview_->SetBounds(0, preview_origin, width(),
- height() - preview_origin);
- } else {
- preview_->SetBounds(0, 0, 0, 0);
- }
- }
-
- // Need to invoke views::View in case any views whose bounds didn't change
- // still need a layout.
- views::View::Layout();
- }
-
- private:
- BrowserView* browser_view_;
- views::View* active_;
- views::View* preview_;
-
- DISALLOW_COPY_AND_ASSIGN(ContentsContainer);
-};
-
///////////////////////////////////////////////////////////////////////////////
// BookmarkExtensionBackground, private:
// This object serves as the views::Background object which is used to layout
@@ -1422,6 +1354,26 @@ void BrowserView::ToggleTabStripMode() {
frame_->TabStripDisplayModeChanged();
}
+void BrowserView::ShowMatchPreview() {
+ if (!preview_container_)
+ preview_container_ = new TabContentsContainer();
+ TabContents* preview_tab_contents =
+ browser_->match_preview()->preview_contents();
+ contents_->SetPreview(preview_container_, preview_tab_contents);
+ preview_container_->ChangeTabContents(preview_tab_contents);
+}
+
+void BrowserView::HideMatchPreview() {
+ if (!preview_container_)
+ return;
+
+ // The contents must be changed before SetPreview is invoked.
+ preview_container_->ChangeTabContents(NULL);
+ contents_->SetPreview(NULL, NULL);
+ delete preview_container_;
+ preview_container_ = NULL;
+}
+
///////////////////////////////////////////////////////////////////////////////
// BrowserView, BrowserWindowTesting implementation:
@@ -1461,25 +1413,6 @@ void BrowserView::Observe(NotificationType type,
}
break;
- case NotificationType::MATCH_PREVIEW_TAB_CONTENTS_CREATED:
- if (Source<TabContents>(source).ptr() ==
- browser_->GetSelectedTabContents()) {
- ShowMatchPreview();
- }
- break;
-
- case NotificationType::TAB_CONTENTS_DESTROYED: {
- if (MatchPreview::IsEnabled()) {
- TabContents* selected_contents = browser_->GetSelectedTabContents();
- if (selected_contents &&
- selected_contents->match_preview()->preview_contents() ==
- Source<TabContents>(source).ptr()) {
- HideMatchPreview();
- }
- }
- break;
- }
-
case NotificationType::SIDEBAR_CHANGED:
if (Details<SidebarContainer>(details)->tab_contents() ==
browser_->GetSelectedTabContents()) {
@@ -1983,13 +1916,6 @@ void BrowserView::Init() {
// We're now initialized and ready to process Layout requests.
ignore_layout_ = false;
-
- registrar_.Add(this,
- NotificationType::MATCH_PREVIEW_TAB_CONTENTS_CREATED,
- NotificationService::AllSources());
- registrar_.Add(this,
- NotificationType::TAB_CONTENTS_DESTROYED,
- NotificationService::AllSources());
}
#if defined(OS_WIN)
@@ -2472,25 +2398,6 @@ void BrowserView::InitHangMonitor() {
#endif
}
-void BrowserView::ShowMatchPreview() {
- if (!preview_container_)
- preview_container_ = new TabContentsContainer();
- contents_->SetPreview(preview_container_);
- preview_container_->ChangeTabContents(
- browser_->GetSelectedTabContents()->match_preview()->preview_contents());
-}
-
-void BrowserView::HideMatchPreview() {
- if (!preview_container_)
- return;
-
- // The contents must be changed before SetPreview is invoked.
- preview_container_->ChangeTabContents(NULL);
- contents_->SetPreview(NULL);
- delete preview_container_;
- preview_container_ = NULL;
-}
-
void BrowserView::ProcessTabSelected(TabContents* new_contents,
bool change_tab_contents) {
// Update various elements that are interested in knowing the current
diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h
index 1d77dff..0ae1122 100644
--- a/chrome/browser/views/frame/browser_view.h
+++ b/chrome/browser/views/frame/browser_view.h
@@ -43,6 +43,7 @@ class BookmarkBarView;
class Browser;
class BrowserBubble;
class BrowserViewLayout;
+class ContentsContainer;
class DownloadShelfView;
class EncodingMenuModel;
class FullscreenExitBubble;
@@ -319,6 +320,8 @@ class BrowserView : public BrowserBubbleHost,
virtual void Copy();
virtual void Paste();
virtual void ToggleTabStripMode();
+ virtual void ShowMatchPreview();
+ virtual void HideMatchPreview();
// Overridden from BrowserWindowTesting:
virtual BookmarkBarView* GetBookmarkBarView() const;
@@ -420,8 +423,6 @@ class BrowserView : public BrowserBubbleHost,
private:
friend class BrowserViewLayout;
- class ContentsContainer;
-
#if defined(OS_WIN)
// Creates the system menu.
void InitSystemMenu();
@@ -493,12 +494,6 @@ class BrowserView : public BrowserBubbleHost,
// Initialize the hung plugin detector.
void InitHangMonitor();
- // Shows the match preview for the selected tab contents.
- void ShowMatchPreview();
-
- // Hides the match preview for the selected tab contents.
- void HideMatchPreview();
-
// Invoked from TabSelectedAt or when the match preview is made active. Is
// |change_tab_contents| is true, |new_contents| is added to the view
// hierarchy, if |change_tab_contents| is false, it's assumed |new_contents|
@@ -521,13 +516,13 @@ class BrowserView : public BrowserBubbleHost,
// | |--------------------------------------------------------------|
// | | Navigation buttons, menus and the address bar (toolbar_) |
// | |--------------------------------------------------------------|
- // | | All infobars (infobar_container_) |
+ // | | All infobars (infobar_container_) * |
// | |--------------------------------------------------------------|
- // | | Bookmarks (bookmark_bar_view_) |
+ // | | Bookmarks (bookmark_bar_view_) * |
// | |--------------------------------------------------------------|
// | |Page content (contents_) || |
// | |--------------------------------------|| Sidebar content |
- // | || contents_container_ or ||| (sidebar_container_) |
+ // | || contents_container_ and/or ||| (sidebar_container_) |
// | || preview_container_ ||| |
// | || |(3) |
// | Tabs (2)|| ||| |
@@ -549,6 +544,11 @@ class BrowserView : public BrowserBubbleHost,
// (2) - tabstrip_, position when side tabs are enabled
// (3) - sidebar_split_
// (4) - contents_split_
+ //
+ // * - The bookmark bar and info bar are swapped when on the new tab page.
+ // Additionally contents_ is positioned on top of the bookmark bar when
+ // the bookmark bar is detached. This is done to allow the
+ // preview_container_ to appear over the bookmark bar.
// Tool/Info bars that we are currently showing. Used for layout.
// active_bookmark_bar_ is either NULL, if the bookmark bar isn't showing,
diff --git a/chrome/browser/views/frame/browser_view_layout.cc b/chrome/browser/views/frame/browser_view_layout.cc
index 0abd70e..ae71abe 100644
--- a/chrome/browser/views/frame/browser_view_layout.cc
+++ b/chrome/browser/views/frame/browser_view_layout.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/views/download_shelf_view.h"
#include "chrome/browser/views/frame/browser_frame.h"
#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/browser/views/frame/contents_container.h"
#include "chrome/browser/views/tabs/side_tab_strip.h"
#include "chrome/browser/views/tabs/tab_strip.h"
#include "chrome/browser/views/toolbar_view.h"
@@ -206,15 +207,18 @@ void BrowserViewLayout::Uninstalled(views::View* host) {}
void BrowserViewLayout::ViewAdded(views::View* host, views::View* view) {
switch (view->GetID()) {
case VIEW_ID_CONTENTS_SPLIT: {
- contents_split_ = view;
- if (SidebarManager::IsSidebarAllowed()) {
- views::View* sidebar_split = contents_split_->GetChildViewAt(0);
- contents_container_ = sidebar_split->GetChildViewAt(0);
- } else {
- contents_container_ = contents_split_->GetChildViewAt(0);
- }
+ contents_split_ = view;
+ // TODO: this is fragile, fix.
+ if (SidebarManager::IsSidebarAllowed()) {
+ views::View* sidebar_split = contents_split_->GetChildViewAt(0);
+ contents_container_ = static_cast<ContentsContainer*>(
+ sidebar_split->GetChildViewAt(0));
+ } else {
+ contents_container_ = static_cast<ContentsContainer*>(
+ contents_split_->GetChildViewAt(0));
}
break;
+ }
case VIEW_ID_INFO_BAR_CONTAINER:
infobar_container_ = view;
break;
@@ -252,6 +256,10 @@ void BrowserViewLayout::Layout(views::View* host) {
top = LayoutToolbar(top);
top = LayoutBookmarkAndInfoBars(top);
int bottom = LayoutDownloadShelf(browser_view_->height());
+ int active_top_margin = GetTopMarginForActiveContent();
+ top -= active_top_margin;
+ bottom += active_top_margin;
+ contents_container_->SetActiveTopMargin(active_top_margin);
LayoutTabContents(top, bottom);
// This must be done _after_ we lay out the TabContents since this
// code calls back into us to find the bounding box the find bar
@@ -276,6 +284,14 @@ gfx::Size BrowserViewLayout::GetPreferredSize(views::View* host) {
//////////////////////////////////////////////////////////////////////////////
// BrowserViewLayout, private:
+Browser* BrowserViewLayout::browser() {
+ return browser_view_->browser();
+}
+
+const Browser* BrowserViewLayout::browser() const {
+ return browser_view_->browser();
+}
+
int BrowserViewLayout::LayoutTabStrip() {
if (!browser_view_->IsTabStripVisible()) {
tabstrip_->SetVisible(false);
@@ -357,13 +373,31 @@ int BrowserViewLayout::LayoutInfoBar(int top) {
return top + height;
}
-// Layout the TabContents container, between the coordinates |top| and
-// |bottom|.
void BrowserViewLayout::LayoutTabContents(int top, int bottom) {
contents_split_->SetBounds(vertical_layout_rect_.x(), top,
vertical_layout_rect_.width(), bottom - top);
}
+int BrowserViewLayout::GetTopMarginForActiveContent() {
+ if (!active_bookmark_bar_ || !browser_view_->IsBookmarkBarVisible() ||
+ !active_bookmark_bar_->IsDetached()) {
+ return 0;
+ }
+
+ if (contents_split_->GetChildViewAt(1) &&
+ contents_split_->GetChildViewAt(1)->IsVisible())
+ return 0;
+
+ if (SidebarManager::IsSidebarAllowed()) {
+ views::View* sidebar_split = contents_split_->GetChildViewAt(0);
+ if (sidebar_split->GetChildViewAt(1) &&
+ sidebar_split->GetChildViewAt(1)->IsVisible())
+ return 0;
+ }
+
+ return active_bookmark_bar_->height();
+}
+
int BrowserViewLayout::LayoutDownloadShelf(int bottom) {
// Re-layout the shelf either if it is visible or if it's close animation
// is currently running.
diff --git a/chrome/browser/views/frame/browser_view_layout.h b/chrome/browser/views/frame/browser_view_layout.h
index 3175bdf..42652ef 100644
--- a/chrome/browser/views/frame/browser_view_layout.h
+++ b/chrome/browser/views/frame/browser_view_layout.h
@@ -6,9 +6,16 @@
#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_VIEW_LAYOUT_H_
#pragma once
-#include "chrome/browser/views/frame/browser_view.h"
#include "views/layout_manager.h"
+class BaseTabStrip;
+class BookmarkBarView;
+class Browser;
+class BrowserView;
+class ContentsContainer;
+class DownloadShelfView;
+class ToolbarView;
+
// The layout manager used in chrome browser.
class BrowserViewLayout : public views::LayoutManager {
public:
@@ -40,12 +47,8 @@ class BrowserViewLayout : public views::LayoutManager {
virtual gfx::Size GetPreferredSize(views::View* host);
protected:
- Browser* browser() {
- return browser_view_->browser();
- }
- const Browser* browser() const {
- return browser_view_->browser();
- }
+ Browser* browser();
+ const Browser* browser() const;
// Layout the TabStrip, returns the coordinate of the bottom of the TabStrip,
// for laying out subsequent controls.
@@ -62,6 +65,11 @@ class BrowserViewLayout : public views::LayoutManager {
// |bottom|.
void LayoutTabContents(int top, int bottom);
+ // Returns the top margin to adjust the contents_container_ by. This is used
+ // to make the bookmark bar and contents_container_ overlap so that the
+ // preview contents hides the bookmark bar.
+ int GetTopMarginForActiveContent();
+
// Layout the Download Shelf, returns the coordinate of the top of the
// control, for laying out the previous control.
int LayoutDownloadShelf(int bottom);
@@ -81,7 +89,7 @@ class BrowserViewLayout : public views::LayoutManager {
BaseTabStrip* tabstrip_;
ToolbarView* toolbar_;
views::View* contents_split_;
- views::View* contents_container_;
+ ContentsContainer* contents_container_;
views::View* infobar_container_;
DownloadShelfView* download_shelf_;
BookmarkBarView* active_bookmark_bar_;
diff --git a/chrome/browser/views/frame/contents_container.cc b/chrome/browser/views/frame/contents_container.cc
new file mode 100644
index 0000000..3d455ef
--- /dev/null
+++ b/chrome/browser/views/frame/contents_container.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2010 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.
+
+#include "chrome/browser/views/frame/contents_container.h"
+
+#include "app/resource_bundle.h"
+#include "chrome/browser/location_bar.h"
+#include "chrome/browser/views/frame/browser_view.h"
+#include "grit/theme_resources.h"
+#include "views/controls/image_view.h"
+#include "views/widget/root_view.h"
+
+#if defined(OS_WIN)
+#include "views/widget/widget_win.h"
+#elif defined(OS_LINUX)
+#include "chrome/browser/gtk/gtk_util.h"
+#include "views/window/window_gtk.h"
+#endif
+
+#if defined(OS_WIN)
+
+class ContentsContainer::TearWindow : public views::WidgetWin {
+ public:
+ explicit TearWindow(ContentsContainer* contents_container)
+ : contents_container_(contents_container) {
+ set_window_style(WS_POPUP | WS_CLIPCHILDREN);
+ set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED);
+ }
+
+ virtual ~TearWindow() {
+ // On windows it's possible for us to be deleted before the
+ // ContentsContainer. If this happens make sure contents_container_ doesn't
+ // attempt to delete us too.
+ if (contents_container_)
+ contents_container_->TearWindowDestroyed();
+ }
+
+ void set_contents_container(ContentsContainer* contents_container) {
+ contents_container_ = contents_container;
+ }
+
+ virtual LRESULT OnMouseActivate(HWND window,
+ UINT hit_test,
+ UINT mouse_message) {
+ // Don't activate the window when the user clicks it.
+ contents_container_->browser_view_->GetLocationBar()->Revert();
+ return MA_NOACTIVATE;
+ }
+
+ private:
+ ContentsContainer* contents_container_;
+
+ DISALLOW_COPY_AND_ASSIGN(TearWindow);
+};
+
+#endif
+
+ContentsContainer::ContentsContainer(BrowserView* browser_view,
+ views::View* active)
+ : browser_view_(browser_view),
+ active_(active),
+ preview_(NULL),
+ preview_tab_contents_(NULL),
+ tear_window_(NULL),
+ active_top_margin_(0) {
+ AddChildView(active_);
+}
+
+ContentsContainer::~ContentsContainer() {
+ DeleteTearWindow();
+}
+
+void ContentsContainer::MakePreviewContentsActiveContents() {
+ active_ = preview_;
+ preview_ = NULL;
+ DeleteTearWindow();
+ Layout();
+}
+
+void ContentsContainer::SetPreview(views::View* preview,
+ TabContents* preview_tab_contents) {
+ if (preview == preview_)
+ return;
+
+ if (preview_) {
+ RemoveChildView(preview_);
+ DeleteTearWindow();
+ }
+ preview_ = preview;
+ preview_tab_contents_ = preview_tab_contents;
+ if (preview_) {
+ AddChildView(preview_);
+ CreateTearWindow();
+ }
+
+ Layout();
+
+ if (preview_)
+ tear_window_->Show(); // Show after we'ved positioned it in Layout.
+}
+
+void ContentsContainer::SetActiveTopMargin(int margin) {
+ if (active_top_margin_ == margin)
+ return;
+
+ active_top_margin_ = margin;
+ // Make sure we layout next time around. We need this in case our bounds
+ // haven't changed.
+ InvalidateLayout();
+}
+
+void ContentsContainer::Layout() {
+ // The active view always gets the full bounds.
+ active_->SetBounds(0, active_top_margin_, width(),
+ std::max(0, height() - active_top_margin_));
+
+ if (preview_) {
+ preview_->SetBounds(0, 0, width(), height());
+ PositionTearWindow();
+ }
+
+ // Need to invoke views::View in case any views whose bounds didn't change
+ // still need a layout.
+ views::View::Layout();
+}
+
+void ContentsContainer::CreateTearWindow() {
+ DCHECK(preview_);
+ tear_window_ = CreateTearWindowImpl();
+
+ views::ImageView* image_view = new views::ImageView();
+ image_view->SetImage(ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_MATCH_PREVIEW_TEAR));
+ tear_window_->SetContentsView(image_view);
+}
+
+#if defined(OS_WIN)
+
+ContentsContainer::TearWindow* ContentsContainer::CreateTearWindowImpl() {
+ TearWindow* widget = new TearWindow(this);
+ widget->Init(browser_view_->GetNativeHandle(), gfx::Rect());
+ return widget;
+}
+
+#elif defined(OS_LINUX)
+
+ContentsContainer::TearWindow* ContentsContainer::CreateTearWindowImpl() {
+ views::WidgetGtk* widget = new views::WidgetGtk(views::WidgetGtk::TYPE_POPUP);
+ widget->MakeTransparent();
+ widget->Init(NULL, gfx::Rect());
+ gtk_util::StackPopupWindow(widget->GetNativeView(),
+ GTK_WIDGET(browser_view_->GetNativeHandle()));
+ return widget;
+}
+
+#endif
+
+void ContentsContainer::PositionTearWindow() {
+ if (!tear_window_)
+ return;
+
+ gfx::Rect vis_bounds = GetVisibleBounds();
+
+ gfx::Size pref = tear_window_->GetRootView()->GetPreferredSize();
+ // Constrain to the the visible bounds as we may be given a different size
+ // than is actually visible.
+ pref.SetSize(std::min(pref.width(), vis_bounds.width()),
+ std::min(pref.height(), vis_bounds.height()));
+
+ gfx::Rect bounds(0, 0, pref.width(), pref.height());
+ bounds.set_x(MirroredLeftPointForRect(bounds));
+
+ gfx::Point origin(bounds.origin());
+ views::View::ConvertPointToScreen(this, &origin);
+
+ tear_window_->SetBounds(gfx::Rect(origin, pref));
+}
+
+void ContentsContainer::DeleteTearWindow() {
+ if (!tear_window_)
+ return;
+
+ tear_window_->Close();
+#if defined(OS_WIN)
+ tear_window_->set_contents_container(NULL);
+#endif
+ // Close deletes the tear window.
+ tear_window_ = NULL;
+}
+
+void ContentsContainer::TearWindowDestroyed() {
+ tear_window_ = NULL;
+}
diff --git a/chrome/browser/views/frame/contents_container.h b/chrome/browser/views/frame/contents_container.h
new file mode 100644
index 0000000..533ad36
--- /dev/null
+++ b/chrome/browser/views/frame/contents_container.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2010 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_VIEWS_FRAME_CONTENTS_CONTAINER_H_
+#define CHROME_BROWSER_VIEWS_FRAME_CONTENTS_CONTAINER_H_
+#pragma once
+
+#include "views/view.h"
+
+class BrowserView;
+class TabContents;
+
+namespace views {
+class Widget;
+}
+
+// ContentsContainer is responsible for managing the TabContents views.
+// ContentsContainer has up to two children: one for the currently active
+// TabContents and one for the match preview TabContents.
+class ContentsContainer : public views::View {
+ public:
+ ContentsContainer(BrowserView* browser_view, views::View* active);
+ virtual ~ContentsContainer();
+
+ // Makes the preview view the active view and nulls out the old active view.
+ // It's assumed the caller will delete or remove the old active view
+ // separately.
+ void MakePreviewContentsActiveContents();
+
+ // Sets the preview view. This does not delete the old.
+ void SetPreview(views::View* preview, TabContents* preview_tab_contents);
+
+ TabContents* preview_tab_contents() const { return preview_tab_contents_; }
+
+ // Sets the active top margin.
+ void SetActiveTopMargin(int margin);
+
+ // View overrides:
+ virtual void Layout();
+
+ private:
+#if defined(OS_WIN)
+ class TearWindow;
+#else
+ typedef views::Widget TearWindow;
+#endif
+
+ // Creates and configures the tear window.
+ void CreateTearWindow();
+
+ // Creates and returns a new TearWindow.
+ TearWindow* CreateTearWindowImpl();
+
+ // Resets the bounds of the tear window.
+ void PositionTearWindow();
+
+ // Closes and deletes the tear window.
+ void DeleteTearWindow();
+
+ // Invoked when the tear window is destroyed.
+ void TearWindowDestroyed();
+
+ BrowserView* browser_view_;
+
+ views::View* active_;
+
+ views::View* preview_;
+
+ TabContents* preview_tab_contents_;
+
+ // Window used to show the page tear.
+ TearWindow* tear_window_;
+
+ // The margin between the top and the active view. This is used to make the
+ // preview overlap the bookmark bar on the new tab page.
+ int active_top_margin_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentsContainer);
+};
+
+#endif // CHROME_BROWSER_VIEWS_FRAME_CONTENTS_CONTAINER_H_
diff --git a/chrome/browser/views/location_bar/location_bar_view.cc b/chrome/browser/views/location_bar/location_bar_view.cc
index 79bb6e8..e970485 100644
--- a/chrome/browser/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/views/location_bar/location_bar_view.cc
@@ -16,10 +16,12 @@
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/alternate_nav_url_fetcher.h"
+#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/match_preview.h"
@@ -98,7 +100,8 @@ LocationBarView::LocationBarView(Profile* profile,
mode_(mode),
show_focus_rect_(false),
bubble_type_(FirstRun::MINIMAL_BUBBLE),
- template_url_model_(NULL) {
+ template_url_model_(NULL),
+ update_match_preview_(true) {
DCHECK(profile_);
SetID(VIEW_ID_LOCATION_BAR);
SetFocusable(true);
@@ -714,13 +717,33 @@ void LocationBarView::OnMouseReleased(const views::MouseEvent& event,
#endif
void LocationBarView::OnAutocompleteWillClosePopup() {
+ if (!update_match_preview_)
+ return;
+
+ MatchPreview* match_preview = delegate_->GetMatchPreview();
+ if (match_preview)
+ match_preview->DestroyPreviewContents();
}
void LocationBarView::OnAutocompleteLosingFocus(
gfx::NativeView view_gaining_focus) {
+ SetSuggestedText(string16());
+
+ MatchPreview* match_preview = delegate_->GetMatchPreview();
+ if (!match_preview)
+ return;
+
+ if (!match_preview->is_active() || !match_preview->preview_contents())
+ return;
+
+ if (ShouldCommitMatchPreviewOnFocusLoss(view_gaining_focus))
+ match_preview->CommitCurrentPreview();
+ else
+ match_preview->DestroyPreviewContents();
}
void LocationBarView::OnAutocompleteWillAccept() {
+ update_match_preview_ = false;
}
void LocationBarView::OnAutocompleteAccept(
@@ -728,34 +751,39 @@ void LocationBarView::OnAutocompleteAccept(
WindowOpenDisposition disposition,
PageTransition::Type transition,
const GURL& alternate_nav_url) {
- if (!url.is_valid())
- return;
-
- location_input_ = UTF8ToWide(url.spec());
- disposition_ = disposition;
- transition_ = transition;
-
- if (command_updater_) {
- if (!alternate_nav_url.is_valid()) {
- command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
- return;
- }
-
- AlternateNavURLFetcher* fetcher =
- new AlternateNavURLFetcher(alternate_nav_url);
- // The AlternateNavURLFetcher will listen for the pending navigation
- // notification that will be issued as a result of the "open URL." It
- // will automatically install itself into that navigation controller.
- command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
- if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
- // I'm not sure this should be reachable, but I'm not also sure enough
- // that it shouldn't to stick in a NOTREACHED(). In any case, this is
- // harmless.
- delete fetcher;
- } else {
- // The navigation controller will delete the fetcher.
+ // WARNING: don't add an early return here. The calls after the if must
+ // happen.
+ if (url.is_valid()) {
+ location_input_ = UTF8ToWide(url.spec());
+ disposition_ = disposition;
+ transition_ = transition;
+
+ if (command_updater_) {
+ if (!alternate_nav_url.is_valid()) {
+ command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
+ } else {
+ AlternateNavURLFetcher* fetcher =
+ new AlternateNavURLFetcher(alternate_nav_url);
+ // The AlternateNavURLFetcher will listen for the pending navigation
+ // notification that will be issued as a result of the "open URL." It
+ // will automatically install itself into that navigation controller.
+ command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
+ if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
+ // I'm not sure this should be reachable, but I'm not also sure enough
+ // that it shouldn't to stick in a NOTREACHED(). In any case, this is
+ // harmless.
+ delete fetcher;
+ } else {
+ // The navigation controller will delete the fetcher.
+ }
+ }
}
}
+
+ if (delegate_->GetMatchPreview())
+ delegate_->GetMatchPreview()->DestroyPreviewContents();
+
+ update_match_preview_ = true;
}
void LocationBarView::OnChanged() {
@@ -765,13 +793,21 @@ void LocationBarView::OnChanged() {
Layout();
SchedulePaint();
- if (MatchPreview::IsEnabled() && GetTabContents() &&
- !profile_->IsOffTheRecord()) {
- PageTransition::Type transition_type;
- GURL url = location_entry_->model()->user_input_in_progress() ?
- location_entry_->model()->CurrentURL(&transition_type) : GURL();
- GetTabContents()->match_preview()->Update(url);
+ MatchPreview* match_preview = delegate_->GetMatchPreview();
+ string16 suggested_text;
+ if (update_match_preview_ && match_preview && GetTabContents()) {
+ if (location_entry_->model()->user_input_in_progress() &&
+ location_entry_->model()->popup_model()->IsOpen()) {
+ match_preview->Update(GetTabContents(),
+ location_entry_->model()->CurrentMatch(),
+ WideToUTF16(location_entry_->GetText()),
+ &suggested_text);
+ } else {
+ match_preview->DestroyPreviewContents();
+ }
}
+
+ SetSuggestedText(suggested_text);
}
void LocationBarView::OnInputInProgress(bool in_progress) {
@@ -1024,7 +1060,7 @@ void LocationBarView::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) {
ShowFirstRunBubbleInternal(bubble_type);
}
-void LocationBarView::SetSuggestedText(const std::wstring& text) {
+void LocationBarView::SetSuggestedText(const string16& text) {
if (!text.empty()) {
if (!suggested_text_view_) {
suggested_text_view_ = new views::Label();
@@ -1032,13 +1068,13 @@ void LocationBarView::SetSuggestedText(const std::wstring& text) {
suggested_text_view_->SetColor(
GetColor(ToolbarModel::NONE,
LocationBarView::DEEMPHASIZED_TEXT));
- suggested_text_view_->SetText(text);
+ suggested_text_view_->SetText(UTF16ToWide(text));
suggested_text_view_->SetFont(location_entry_->GetFont());
AddChildView(suggested_text_view_);
- } else if (suggested_text_view_->GetText() == text) {
+ } else if (suggested_text_view_->GetText() == UTF16ToWide(text)) {
return;
} else {
- suggested_text_view_->SetText(text);
+ suggested_text_view_->SetText(UTF16ToWide(text));
}
} else if (suggested_text_view_) {
delete suggested_text_view_;
@@ -1141,3 +1177,28 @@ void LocationBarView::OnTemplateURLModelChanged() {
ShowFirstRunBubble(bubble_type_);
}
+bool LocationBarView::ShouldCommitMatchPreviewOnFocusLoss(
+ gfx::NativeView view_gaining_focus) {
+ // The MatchPreview is active. Destroy it if the user didn't click on the
+ // RenderWidgetHostView (or one of its children).
+#if defined(OS_WIN)
+ MatchPreview* match_preview = delegate_->GetMatchPreview();
+ if (!view_gaining_focus ||
+ !match_preview->preview_contents()->GetRenderWidgetHostView()) {
+ return false;
+ }
+ RenderWidgetHostView* rwhv =
+ match_preview->preview_contents()->GetRenderWidgetHostView();
+ gfx::NativeView rwhv_native_view = rwhv->GetNativeView();
+ gfx::NativeView view_gaining_focus_ancestor = view_gaining_focus;
+ while (view_gaining_focus_ancestor &&
+ view_gaining_focus_ancestor != rwhv_native_view) {
+ view_gaining_focus_ancestor = ::GetParent(view_gaining_focus_ancestor);
+ }
+ return view_gaining_focus_ancestor != NULL;
+#else
+ // TODO: implement me.
+ NOTIMPLEMENTED();
+ return false;
+#endif
+}
diff --git a/chrome/browser/views/location_bar/location_bar_view.h b/chrome/browser/views/location_bar/location_bar_view.h
index 120de8d..d8c7976 100644
--- a/chrome/browser/views/location_bar/location_bar_view.h
+++ b/chrome/browser/views/location_bar/location_bar_view.h
@@ -38,6 +38,7 @@ class ExtensionAction;
class GURL;
class KeywordHintView;
class LocationIconView;
+class MatchPreview;
class PageActionWithBadgeView;
class Profile;
class SelectedKeywordView;
@@ -72,6 +73,9 @@ class LocationBarView : public LocationBar,
// Should return the current tab contents.
virtual TabContents* GetTabContents() = 0;
+ // Returns the MatchPreview, or NULL if there isn't one.
+ virtual MatchPreview* GetMatchPreview() = 0;
+
// Called by the location bar view when the user starts typing in the edit.
// This forces our security style to be UNKNOWN for the duration of the
// editing.
@@ -201,7 +205,7 @@ class LocationBarView : public LocationBar,
// Overridden from LocationBar:
virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type);
- virtual void SetSuggestedText(const std::wstring& text);
+ virtual void SetSuggestedText(const string16& text);
virtual std::wstring GetInputString() const;
virtual WindowOpenDisposition GetWindowOpenDisposition() const;
virtual PageTransition::Type GetPageTransition() const;
@@ -293,6 +297,11 @@ class LocationBarView : public LocationBar,
// Helper to show the first run info bubble.
void ShowFirstRunBubbleInternal(FirstRun::BubbleType bubble_type);
+ // Returns true if the CommitMatchPreview should be invoked on the
+ // MatchPreview as the result of a focus loss. If this returns false
+ // DestroyPreviewContents is invoked.
+ bool ShouldCommitMatchPreviewOnFocusLoss(gfx::NativeView view_gaining_focus);
+
// Current profile. Not owned by us.
Profile* profile_;
@@ -381,6 +390,12 @@ class LocationBarView : public LocationBar,
scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_;
#endif
+ // Should the match preview be updated? This is set to false in
+ // OnAutocompleteWillAccept and true in OnAutocompleteAccept. This is needed
+ // as prior to accepting an autocomplete suggestion the model is reverted
+ // which triggers resetting the match preview.
+ bool update_match_preview_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(LocationBarView);
};
diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc
index ccdc7e2..d1ad65b 100644
--- a/chrome/browser/views/toolbar_view.cc
+++ b/chrome/browser/views/toolbar_view.cc
@@ -270,6 +270,10 @@ TabContents* ToolbarView::GetTabContents() {
return browser_->GetSelectedTabContents();
}
+MatchPreview* ToolbarView::GetMatchPreview() {
+ return browser_->match_preview();
+}
+
void ToolbarView::OnInputInProgress(bool in_progress) {
// The edit should make sure we're only notified when something changes.
DCHECK(model_->input_in_progress() != in_progress);
diff --git a/chrome/browser/views/toolbar_view.h b/chrome/browser/views/toolbar_view.h
index 2bded31..d95111b 100644
--- a/chrome/browser/views/toolbar_view.h
+++ b/chrome/browser/views/toolbar_view.h
@@ -88,6 +88,7 @@ class ToolbarView : public AccessibleToolbarView,
// Overridden from LocationBarView::Delegate:
virtual TabContents* GetTabContents();
+ virtual MatchPreview* GetMatchPreview();
virtual void OnInputInProgress(bool in_progress);
// Overridden from AnimationDelegate: