diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-11 04:03:57 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-11 04:03:57 +0000 |
commit | fd2b9cec9b6eed50f8fc1fcdf72866733fe57f45 (patch) | |
tree | 620a3ff359c4007f30c54f292de5a546739a570a /chrome | |
parent | 7ab36c4f07b585449febcc6f2c59a9f5a0a40eed (diff) | |
download | chromium_src-fd2b9cec9b6eed50f8fc1fcdf72866733fe57f45.zip chromium_src-fd2b9cec9b6eed50f8fc1fcdf72866733fe57f45.tar.gz chromium_src-fd2b9cec9b6eed50f8fc1fcdf72866733fe57f45.tar.bz2 |
Adds support for showing the match preview on views. It's behind the
flag --enable-match-preview. There is still a lot of details to get it
working good enough, but this is a good point to check some stuff in.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/3105004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55665 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/browser.cc | 11 | ||||
-rw-r--r-- | chrome/browser/browser.h | 1 | ||||
-rw-r--r-- | chrome/browser/tab_contents/match_preview.cc | 192 | ||||
-rw-r--r-- | chrome/browser/tab_contents/match_preview.h | 80 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 4 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.h | 6 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_delegate.cc | 3 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_delegate.h | 5 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model.cc | 43 | ||||
-rw-r--r-- | chrome/browser/tabs/tab_strip_model.h | 37 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_view.cc | 217 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_view.h | 28 | ||||
-rw-r--r-- | chrome/browser/views/location_bar/location_bar_view.cc | 8 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 4 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 3 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 | ||||
-rw-r--r-- | chrome/common/notification_type.h | 4 |
17 files changed, 602 insertions, 45 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 83c6c48..6083fb0 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -70,6 +70,7 @@ #include "chrome/browser/sync/sync_ui_util.h" #include "chrome/browser/tab_closeable_state_watcher.h" #include "chrome/browser/tab_contents/interstitial_page.h" +#include "chrome/browser/tab_contents/match_preview.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" @@ -2944,6 +2945,16 @@ 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: diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 1041735..0a7c0ab 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -741,6 +741,7 @@ class Browser : public TabStripModelDelegate, int32 page_id); virtual Browser* GetBrowser(); virtual void ContentTypeChanged(TabContents* source); + virtual void CommitMatchPreview(TabContents* source); // Overridden from SelectFileDialog::Listener: virtual void FileSelected(const FilePath& path, int index, void* params); diff --git a/chrome/browser/tab_contents/match_preview.cc b/chrome/browser/tab_contents/match_preview.cc new file mode 100644 index 0000000..3c0c43e --- /dev/null +++ b/chrome/browser/tab_contents/match_preview.cc @@ -0,0 +1,192 @@ +// 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/tab_contents/match_preview.h" + +#include <algorithm> + +#include "base/command_line.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/common/chrome_switches.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/page_transition_types.h" +#include "chrome/common/renderer_preferences.h" +#include "ipc/ipc_message.h" + +class MatchPreview::TabContentsDelegateImpl : public TabContentsDelegate { + public: + explicit TabContentsDelegateImpl(MatchPreview* match_preview) + : match_preview_(match_preview) { + } + + virtual void OpenURLFromTab(TabContents* source, + const GURL& url, const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition) {} + virtual void NavigationStateChanged(const TabContents* source, + unsigned changed_flags) {} + 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 LoadingStateChanged(TabContents* source) {} + virtual void CloseContents(TabContents* source) {} + virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {} + virtual void DetachContents(TabContents* source) {} + virtual bool IsPopup(const TabContents* source) const { + return false; + } + virtual TabContents* GetConstrainingContents(TabContents* source) { + return NULL; + } + virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {} + virtual void URLStarredChanged(TabContents* source, bool starred) {} + virtual void UpdateTargetURL(TabContents* source, const GURL& url) {} + virtual void ContentsMouseEvent( + TabContents* source, const gfx::Point& location, bool motion) {} + virtual void ContentsZoomChange(bool zoom_in) {} + virtual void OnContentSettingsChange(TabContents* source) {} + virtual bool IsApplication() const { return false; } + 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(); + } + virtual void ShowHtmlDialog(HtmlDialogUIDelegate* delegate, + gfx::NativeWindow parent_window) {} + virtual void BeforeUnloadFired(TabContents* tab, + bool proceed, + bool* proceed_to_fire_unload) {} + virtual void ForwardMessageToExternalHost(const std::string& message, + const std::string& origin, + const std::string& target) {} + virtual bool IsExternalTabContainer() const { return false; } + virtual void SetFocusToLocationBar(bool select_all) {} + virtual void RenderWidgetShowing() {} + virtual ExtensionFunctionDispatcher* CreateExtensionFunctionDispatcher( + RenderViewHost* render_view_host, + const std::string& extension_id) { + return NULL; + } + 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; } + virtual void OnStartDownload(DownloadItem* download, TabContents* tab) {} + virtual bool HandleContextMenu(const ContextMenuParams& params) { + return false; + } + virtual bool ExecuteContextMenuCommand(int command) { + return false; + } + virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile) {} + virtual void ShowPageInfo(Profile* profile, + const GURL& url, + const NavigationEntry::SSLStatus& ssl, + bool show_history) {} + virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, + bool* is_keyboard_shortcut) { + return false; + } + virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {} + virtual void ShowRepostFormWarningDialog(TabContents* tab_contents) {} + virtual void ShowContentSettingsWindow(ContentSettingsType content_type) {} + virtual void ShowCollectedCookiesDialog(TabContents* tab_contents) {} + virtual bool OnGoToEntryOffset(int offset) { return false; } + virtual bool ShouldAddNavigationsToHistory() const { return false; } + virtual void OnDidGetApplicationInfo(TabContents* tab_contents, + int32 page_id) {} + virtual Browser* GetBrowser() { return NULL; } + virtual gfx::NativeWindow GetFrameNativeWindow() { + return match_preview_->host_->delegate() ? + match_preview_->host_->delegate()->GetFrameNativeWindow() : NULL; + } + virtual void TabContentsCreated(TabContents* new_contents) {} + virtual bool infobars_enabled() { return false; } + virtual bool ShouldEnablePreferredSizeNotifications() { return false; } + virtual void UpdatePreferredSize(const gfx::Size& pref_size) {} + virtual void ContentTypeChanged(TabContents* source) {} + + private: + MatchPreview* match_preview_; + + DISALLOW_COPY_AND_ASSIGN(TabContentsDelegateImpl); +}; + +MatchPreview::MatchPreview(TabContents* host) : host_(host) { + 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); +} + +// static +bool MatchPreview::IsEnabled() { + static bool enabled = false; + static bool checked = false; + if (!checked) { + checked = true; + enabled = CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableMatchPreview); + } + return enabled; +} + +void MatchPreview::Update(const GURL& url) { + if (url_ == url) + return; + + url_ = url; + + if (url_.is_empty() || !url_.is_valid()) { + DestroyPreviewContents(); + return; + } + + if (!preview_contents_.get()) { + preview_contents_.reset( + new TabContents(host_->profile(), NULL, MSG_ROUTING_NONE, NULL)); + preview_contents_->set_delegate(delegate_.get()); + NotificationService::current()->Notify( + NotificationType::MATCH_PREVIEW_TAB_CONTENTS_CREATED, + Source<TabContents>(host_), + NotificationService::NoDetails()); + } + + // TODO: figure out transition type. + preview_contents_->controller().LoadURL(url, GURL(), + PageTransition::GENERATED); +} + +void MatchPreview::DestroyPreviewContents() { + url_ = GURL(); + preview_contents_.reset(NULL); +} + +void MatchPreview::CommitCurrentPreview() { + DCHECK(preview_contents_.get()); + if (host_->delegate()) + host_->delegate()->CommitMatchPreview(host_); +} + +TabContents* MatchPreview::ReleasePreviewContents() { + url_ = GURL(); + return preview_contents_.release(); +} diff --git a/chrome/browser/tab_contents/match_preview.h b/chrome/browser/tab_contents/match_preview.h new file mode 100644 index 0000000..cc6605b --- /dev/null +++ b/chrome/browser/tab_contents/match_preview.h @@ -0,0 +1,80 @@ +// 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_H_ +#define CHROME_BROWSER_TAB_CONTENTS_MATCH_PREVIEW_H_ + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "googleurl/src/gurl.h" + +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. +// +// 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. +class MatchPreview { + public: + explicit MatchPreview(TabContents* host); + ~MatchPreview(); + + // Is MatchPreview enabled? + static bool IsEnabled(); + + // 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. + void Update(const GURL& url); + + // Destroys the preview TabContents. Does nothing if the preview TabContents + // has not been created. + void DestroyPreviewContents(); + + // Invoked when the user does some gesture that should trigger making the + // current previewed page the permanent page. + 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(); + + // The TabContents we're maintaining the preview for. + TabContents* host() { return host_; } + + // The preview TabContents; may be null. + TabContents* preview_contents() { return preview_contents_.get(); } + + private: + class TabContentsDelegateImpl; + + // 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_; + + // The preview TabContents; may be null. + scoped_ptr<TabContents> preview_contents_; + + DISALLOW_COPY_AND_ASSIGN(MatchPreview); +}; + +#endif // CHROME_BROWSER_TAB_CONTENTS_MATCH_PREVIEW_H_ diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 42da773..076ced4 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -69,6 +69,7 @@ #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" @@ -424,6 +425,9 @@ 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 ab4cf56..ac73e96 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -68,6 +68,7 @@ class DownloadItem; class Extension; class InfoBarDelegate; class LoadNotificationDetails; +class MatchPreview; class OmniboxSearchHint; class PasswordManager; class PluginInstaller; @@ -160,6 +161,9 @@ class TabContents : public PageNavigator, // Returns the TabContentsSSLHelper, creating if it 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(); } @@ -1261,6 +1265,8 @@ 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 30bee94..9c89cd3 100644 --- a/chrome/browser/tab_contents/tab_contents_delegate.cc +++ b/chrome/browser/tab_contents/tab_contents_delegate.cc @@ -167,5 +167,8 @@ void TabContentsDelegate::UpdatePreferredSize(const gfx::Size& pref_size) { void TabContentsDelegate::ContentTypeChanged(TabContents* source) { } +void TabContentsDelegate::CommitMatchPreview(TabContents* source) { +} + TabContentsDelegate::~TabContentsDelegate() { } diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h index 9b2230e..a6b2597 100644 --- a/chrome/browser/tab_contents/tab_contents_delegate.h +++ b/chrome/browser/tab_contents/tab_contents_delegate.h @@ -277,6 +277,11 @@ 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); + protected: virtual ~TabContentsDelegate(); }; diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc index 8ac8fc4..269de35 100644 --- a/chrome/browser/tabs/tab_strip_model.cc +++ b/chrome/browser/tabs/tab_strip_model.cc @@ -82,6 +82,13 @@ void TabStripModelObserver::TabReplacedAt(TabContents* old_contents, int index) { } +void TabStripModelObserver::TabReplacedAt(TabContents* old_contents, + TabContents* new_contents, + int index, + TabReplaceType type) { + TabReplacedAt(old_contents, new_contents, index); +} + void TabStripModelObserver::TabPinnedStateChanged(TabContents* contents, int index) { } @@ -233,6 +240,13 @@ void TabStripModel::InsertTabContentsAt(int index, ChangeSelectedContentsFrom(selected_contents, index, false); } +void TabStripModel::ReplaceTabContentsAt( + int index, + TabContents* new_contents, + TabStripModelObserver::TabReplaceType type) { + delete ReplaceTabContentsAtImpl(index, new_contents, type); +} + void TabStripModel::ReplaceNavigationControllerAt( int index, NavigationController* controller) { // This appears to be OK with no flicker since no redraw event @@ -1043,14 +1057,10 @@ bool TabStripModel::ShouldMakePhantomOnClose(int index) { } void TabStripModel::MakePhantom(int index) { - TabContents* old_contents = GetContentsAt(index); - TabContents* new_contents = old_contents->CloneAndMakePhantom(); - - contents_data_[index]->contents = new_contents; - - // And notify observers. - FOR_EACH_OBSERVER(TabStripModelObserver, observers_, - TabReplacedAt(old_contents, new_contents, index)); + // MakePhantom is called when the TabContents is being destroyed so we don't + // need to do anything with the returned value from ReplaceTabContentsAtImpl. + ReplaceTabContentsAtImpl(index, GetContentsAt(index)->CloneAndMakePhantom(), + TabStripModelObserver::REPLACE_MADE_PHANTOM); if (selected_index_ == index && HasNonPhantomTabs()) { // Change the selection, otherwise we're going to force the phantom tab @@ -1095,3 +1105,20 @@ bool TabStripModel::OpenerMatches(const TabContentsData* data, bool use_group) { return data->opener == opener || (use_group && data->group == opener); } + +TabContents* TabStripModel::ReplaceTabContentsAtImpl( + int index, + TabContents* new_contents, + TabStripModelObserver::TabReplaceType type) { + // TODO: this should reset group/opener of any tabs that point at + // old_contents. + DCHECK(ContainsIndex(index)); + + TabContents* old_contents = GetContentsAt(index); + + contents_data_[index]->contents = new_contents; + + FOR_EACH_OBSERVER(TabStripModelObserver, observers_, + TabReplacedAt(old_contents, new_contents, index, type)); + return old_contents; +} diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h index f26af59..542b27f 100644 --- a/chrome/browser/tabs/tab_strip_model.h +++ b/chrome/browser/tabs/tab_strip_model.h @@ -54,6 +54,18 @@ class TabStripModelObserver { ALL }; + // Enum used by ReplaceTabContentsAt. + // TODO(sky): TabReplaceType should be declared outside the scope of + // the observer. I need to put all the enums in a namespace and cleanup this + // file. + enum TabReplaceType { + // The replace is the result of the tab being made phantom. + REPLACE_MADE_PHANTOM, + + // The replace is the result of the match preview being committed. + REPLACE_MATCH_PREVIEW + }; + // A new TabContents was inserted into the TabStripModel at the specified // index. |foreground| is whether or not it was opened in the foreground // (selected). @@ -100,8 +112,18 @@ class TabStripModelObserver { // The tab contents was replaced at the specified index. This is invoked when // a tab becomes phantom. See description of phantom tabs in class description // of TabStripModel for details. + // TODO(sky): nuke this in favor of the 4 arg variant. + virtual void TabReplacedAt(TabContents* old_contents, + TabContents* new_contents, + int index); + + // The tab contents was replaced at the specified index. |type| describes + // the type of replace. + // This invokes TabReplacedAt with three args. virtual void TabReplacedAt(TabContents* old_contents, - TabContents* new_contents, int index); + TabContents* new_contents, + int index, + TabReplaceType type); // Invoked when the pinned state of a tab changes. This is not invoked if the // tab ends up moving as a result of the mini state changing. @@ -433,6 +455,12 @@ class TabStripModel : public NotificationObserver { void ReplaceNavigationControllerAt(int index, NavigationController* controller); + // Replaces the tab contents at |index| with |new_contents|. |type| is passed + // to the observer. This deletes the TabContents currently at |index|. + void ReplaceTabContentsAt(int index, + TabContents* new_contents, + TabStripModelObserver::TabReplaceType type); + // Detaches the TabContents at the specified index from this strip. The // TabContents is not destroyed, just removed from display. The caller is // responsible for doing something with it (e.g. stuffing it into another @@ -725,6 +753,13 @@ class TabStripModel : public NotificationObserver { const NavigationController* opener, bool use_group); + // Does the work for ReplaceTabContentsAt returning the old TabContents. + // The caller owns the returned TabContents. + TabContents* ReplaceTabContentsAtImpl( + int index, + TabContents* new_contents, + TabStripModelObserver::TabReplaceType type); + // Our delegate. TabStripModelDelegate* delegate_; diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index 3034a38..8c1189c 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -15,6 +15,8 @@ #include "base/utf_string_conversions.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/app_modal_dialog_queue.h" +#include "chrome/browser/autocomplete/autocomplete_popup_model.h" +#include "chrome/browser/autocomplete/autocomplete_popup_view.h" #include "chrome/browser/automation/ui_controls.h" #include "chrome/browser/bookmarks/bookmark_utils.h" #include "chrome/browser/browser_list.h" @@ -27,6 +29,7 @@ #include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/sessions/tab_restore_service.h" +#include "chrome/browser/tab_contents/match_preview.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/browser/view_ids.h" @@ -127,6 +130,71 @@ 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); + } + } + } + + 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 @@ -416,6 +484,8 @@ BrowserView::BrowserView(Browser* browser) infobar_container_(NULL), contents_container_(NULL), devtools_container_(NULL), + preview_container_(NULL), + contents_(NULL), contents_split_(NULL), initialized_(false), ignore_layout_(true), @@ -518,7 +588,7 @@ gfx::Rect BrowserView::GetToolbarBounds() const { } gfx::Rect BrowserView::GetClientAreaBounds() const { - gfx::Rect container_bounds = contents_container_->bounds(); + gfx::Rect container_bounds = contents_->bounds(); gfx::Point container_origin = container_bounds.origin(); ConvertPointToView(this, GetParent(), &container_origin); container_bounds.set_origin(container_origin); @@ -1320,12 +1390,36 @@ ToolbarView* BrowserView::GetToolbarView() const { void BrowserView::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { - if (type == NotificationType::PREF_CHANGED && - *Details<std::string>(details).ptr() == prefs::kShowBookmarkBar) { - if (MaybeShowBookmarkBar(browser_->GetSelectedTabContents())) - Layout(); - } else { - NOTREACHED() << "Got a notification we didn't register for!"; + switch (type.value) { + case NotificationType::PREF_CHANGED: + if (*Details<std::string>(details).ptr() == prefs::kShowBookmarkBar && + MaybeShowBookmarkBar(browser_->GetSelectedTabContents())) { + Layout(); + } + 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; + } + + default: + NOTREACHED() << "Got a notification we didn't register for!"; + break; } } @@ -1360,34 +1454,29 @@ void BrowserView::TabSelectedAt(TabContents* old_contents, bool user_gesture) { DCHECK(old_contents != new_contents); - // Update various elements that are interested in knowing the current - // TabContents. - - // When we toggle the NTP floating bookmarks bar and/or the info bar, - // we don't want any TabContents to be attached, so that we - // avoid an unnecessary resize and re-layout of a TabContents. - contents_container_->ChangeTabContents(NULL); - infobar_container_->ChangeTabContents(new_contents); - UpdateUIForContents(new_contents); - contents_container_->ChangeTabContents(new_contents); + ProcessTabSelected(new_contents, true); +} - UpdateDevToolsForContents(new_contents); - // TODO(beng): This should be called automatically by ChangeTabContents, but I - // am striving for parity now rather than cleanliness. This is - // required to make features like Duplicate Tab, Undo Close Tab, - // etc not result in sad tab. - new_contents->DidBecomeSelected(); - if (BrowserList::GetLastActive() == browser_ && - !browser_->tabstrip_model()->closing_all() && GetWindow()->IsVisible()) { - // We only restore focus if our window is visible, to avoid invoking blur - // handlers when we are eventually shown. - new_contents->view()->RestoreFocus(); +void BrowserView::TabReplacedAt(TabContents* old_contents, + TabContents* new_contents, + int index, + TabStripModelObserver::TabReplaceType type) { + if (type != TabStripModelObserver::REPLACE_MATCH_PREVIEW || + index != browser_->tabstrip_model()->selected_index()) { + return; } - // Update all the UI bits. - UpdateTitleBar(); - UpdateToolbar(new_contents, true); - UpdateUIForContents(new_contents); + // Swap the 'active' and 'preview' and delete what was the active. + contents_->MakePreviewContentsActiveContents(); + TabContentsContainer* old_container = contents_container_; + contents_container_ = preview_container_; + old_container->ChangeTabContents(NULL); + delete old_container; + preview_container_ = NULL; + + // Update the UI for what was the preview contents and is now active. Pass in + // false to ProcessTabSelected as new_contents is already parented correctly. + ProcessTabSelected(new_contents, false); } void BrowserView::TabStripEmpty() { @@ -1759,11 +1848,12 @@ void BrowserView::Init() { AddChildView(infobar_container_); contents_container_ = new TabContentsContainer; + contents_ = new ContentsContainer(this, contents_container_); devtools_container_ = new TabContentsContainer; devtools_container_->SetID(VIEW_ID_DEV_TOOLS_DOCKED); devtools_container_->SetVisible(false); contents_split_ = new views::SingleSplitView( - contents_container_, + contents_, devtools_container_, views::SingleSplitView::VERTICAL_SPLIT); contents_split_->SetID(VIEW_ID_CONTENTS_SPLIT); @@ -1808,6 +1898,13 @@ 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) @@ -2234,6 +2331,60 @@ 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 + // TabContents. + + // When we toggle the NTP floating bookmarks bar and/or the info bar, + // we don't want any TabContents to be attached, so that we + // avoid an unnecessary resize and re-layout of a TabContents. + if (change_tab_contents) + contents_container_->ChangeTabContents(NULL); + infobar_container_->ChangeTabContents(new_contents); + UpdateUIForContents(new_contents); + if (change_tab_contents) + contents_container_->ChangeTabContents(new_contents); + + UpdateDevToolsForContents(new_contents); + // TODO(beng): This should be called automatically by ChangeTabContents, but I + // am striving for parity now rather than cleanliness. This is + // required to make features like Duplicate Tab, Undo Close Tab, + // etc not result in sad tab. + new_contents->DidBecomeSelected(); + if (BrowserList::GetLastActive() == browser_ && + !browser_->tabstrip_model()->closing_all() && GetWindow()->IsVisible()) { + // We only restore focus if our window is visible, to avoid invoking blur + // handlers when we are eventually shown. + new_contents->view()->RestoreFocus(); + } + + // Update all the UI bits. + UpdateTitleBar(); + UpdateToolbar(new_contents, true); + UpdateUIForContents(new_contents); +} + #if !defined(OS_CHROMEOS) // static BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) { diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index 37657f0..d2cadda 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -24,6 +24,7 @@ #include "chrome/browser/views/tabs/tab_strip.h" #include "chrome/browser/views/tabs/base_tab_strip.h" #include "chrome/browser/views/unhandled_keyboard_event_handler.h" +#include "chrome/common/notification_registrar.h" #include "gfx/native_widget_types.h" #include "views/window/client_view.h" #include "views/window/window_delegate.h" @@ -335,6 +336,10 @@ class BrowserView : public BrowserBubbleHost, TabContents* new_contents, int index, bool user_gesture); + virtual void TabReplacedAt(TabContents* old_contents, + TabContents* new_contents, + int index, + TabStripModelObserver::TabReplaceType type); virtual void TabStripEmpty(); // Overridden from menus::SimpleMenuModel::Delegate: @@ -412,6 +417,8 @@ class BrowserView : public BrowserBubbleHost, private: friend class BrowserViewLayout; + class ContentsContainer; + #if defined(OS_WIN) // Creates the system menu. void InitSystemMenu(); @@ -477,8 +484,17 @@ class BrowserView : public BrowserBubbleHost, // Initialize the hung plugin detector. void InitHangMonitor(); - // Initialize class statics. - static void InitClass(); + // 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| + // has already been added to the view hierarchy. + void ProcessTabSelected(TabContents* new_contents, bool change_tab_contents); // Last focused view that issued a tab traversal. int last_focused_view_storage_id_; @@ -515,6 +531,12 @@ class BrowserView : public BrowserBubbleHost, // The view that contains devtools window for the selected TabContents. TabContentsContainer* devtools_container_; + // The view that contains the match preview TabContents. + TabContentsContainer* preview_container_; + + // The view managing both the contents_container_ and preview_container_. + ContentsContainer* contents_; + // Split view containing the contents container and devtools container. views::SingleSplitView* contents_split_; @@ -576,6 +598,8 @@ class BrowserView : public BrowserBubbleHost, scoped_ptr<AccessibleViewHelper> accessible_view_helper_; + NotificationRegistrar registrar_; + DISALLOW_COPY_AND_ASSIGN(BrowserView); }; diff --git a/chrome/browser/views/location_bar/location_bar_view.cc b/chrome/browser/views/location_bar/location_bar_view.cc index f42d9af..e8d8e05 100644 --- a/chrome/browser/views/location_bar/location_bar_view.cc +++ b/chrome/browser/views/location_bar/location_bar_view.cc @@ -19,6 +19,7 @@ #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/tab_contents/match_preview.h" #include "chrome/browser/view_ids.h" #include "chrome/browser/views/browser_dialogs.h" #include "chrome/browser/views/location_bar/content_setting_image_view.h" @@ -712,6 +713,13 @@ void LocationBarView::OnChanged() { location_entry_->GetIcon())); Layout(); SchedulePaint(); + + if (MatchPreview::IsEnabled() && GetTabContents() && + !profile_->IsOffTheRecord()) { + GURL url = location_entry_->model()->user_input_in_progress() ? + location_entry_->model()->CurrentURL() : GURL(); + GetTabContents()->match_preview()->Update(url); + } } void LocationBarView::OnInputInProgress(bool in_progress) { diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 375120e..7e9d7fe 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2484,6 +2484,8 @@ 'browser/tab_contents/interstitial_page.h', 'browser/tab_contents/language_state.h', 'browser/tab_contents/language_state.cc', + 'browser/tab_contents/match_preview.cc', + 'browser/tab_contents/match_preview.h', 'browser/tab_contents/navigation_controller.cc', 'browser/tab_contents/navigation_controller.h', 'browser/tab_contents/navigation_entry.cc', @@ -2514,8 +2516,8 @@ 'browser/tab_contents/tab_contents_view_gtk.h', 'browser/tab_contents/tab_contents_view_mac.h', 'browser/tab_contents/tab_contents_view_mac.mm', - 'browser/tab_contents/tab_specific_content_settings.h', 'browser/tab_contents/tab_specific_content_settings.cc', + 'browser/tab_contents/tab_specific_content_settings.h', 'browser/tab_contents/tab_util.cc', 'browser/tab_contents/tab_util.h', 'browser/tab_contents/thumbnail_generator.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 27e5cf4..34b8be9 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -376,6 +376,9 @@ const char kEnableGPURendering[] = "enable-gpu-rendering"; // builds. const char kEnableLogging[] = "enable-logging"; +// Is match preview enabled? +const char kEnableMatchPreview[] = "enable-match-preview"; + // Allows reporting memory info (JS heap size) to page. const char kEnableMemoryInfo[] = "enable-memory-info"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 362a3a6..fbc8b81 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -122,6 +122,7 @@ extern const char kEnableIndexedDatabase[]; extern const char kEnableInMemoryURLIndex[]; extern const char kEnableIPv6[]; extern const char kEnableLogging[]; +extern const char kEnableMatchPreview[]; extern const char kEnableMemoryInfo[]; extern const char kEnableMonitorProfile[]; extern const char kEnableNaCl[]; diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index ed8b2b2..7c19c9e 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -393,6 +393,10 @@ class NotificationType { // pointer. RENDER_VIEW_HOST_CREATED_FOR_TAB, + // Sent when MatchPreview creates the preview TabContents. The source is the + // TabContents the MatchPreview is associated with. + MATCH_PREVIEW_TAB_CONTENTS_CREATED, + // Stuff inside the tabs --------------------------------------------------- // This message is sent after a constrained window has been closed. The |