diff options
author | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-24 19:27:32 +0000 |
---|---|---|
committer | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-24 19:27:32 +0000 |
commit | 28efc58634459b8fc65ee1a5cb00a4351e7179b9 (patch) | |
tree | 587568b6b0845d11b2238ebb30671d467cf34c81 /chrome_frame | |
parent | 3b17959e51578bb2fba9f22100a199c436e31d5d (diff) | |
download | chromium_src-28efc58634459b8fc65ee1a5cb00a4351e7179b9.zip chromium_src-28efc58634459b8fc65ee1a5cb00a4351e7179b9.tar.gz chromium_src-28efc58634459b8fc65ee1a5cb00a4351e7179b9.tar.bz2 |
Update the Ready Mode UI in response to feedback from UI leads, Chrome Frame team.
BUG=None
TEST=chrome_frame_unittests --gtest_filter=Ready*
Review URL: http://codereview.chromium.org/6314016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72366 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
-rw-r--r-- | chrome_frame/chrome_frame.gyp | 1 | ||||
-rw-r--r-- | chrome_frame/ready_mode/internal/ready_prompt_content.cc | 17 | ||||
-rw-r--r-- | chrome_frame/ready_mode/internal/ready_prompt_content.h | 9 | ||||
-rw-r--r-- | chrome_frame/ready_mode/internal/ready_prompt_window.cc | 62 | ||||
-rw-r--r-- | chrome_frame/ready_mode/internal/ready_prompt_window.h | 37 | ||||
-rw-r--r-- | chrome_frame/ready_mode/internal/url_launcher.h | 20 | ||||
-rw-r--r-- | chrome_frame/ready_mode/ready_mode.cc | 35 | ||||
-rw-r--r-- | chrome_frame/test/ready_mode_unittest.cc | 33 |
8 files changed, 168 insertions, 46 deletions
diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp index a50096f..e1596c8 100644 --- a/chrome_frame/chrome_frame.gyp +++ b/chrome_frame/chrome_frame.gyp @@ -872,6 +872,7 @@ 'ready_mode/internal/ready_prompt_window.h', 'ready_mode/internal/registry_ready_mode_state.cc', 'ready_mode/internal/registry_ready_mode_state.h', + 'ready_mode/internal/url_launcher.h', 'ready_mode/ready_mode.cc', 'ready_mode/ready_mode.h', 'register_bho.rgs', diff --git a/chrome_frame/ready_mode/internal/ready_prompt_content.cc b/chrome_frame/ready_mode/internal/ready_prompt_content.cc index 4764e63..52ab70f 100644 --- a/chrome_frame/ready_mode/internal/ready_prompt_content.cc +++ b/chrome_frame/ready_mode/internal/ready_prompt_content.cc @@ -4,15 +4,15 @@ #include "chrome_frame/ready_mode/internal/ready_prompt_content.h" -#include <atlbase.h> -#include <atlwin.h> - #include "base/logging.h" #include "chrome_frame/ready_mode/internal/ready_mode_state.h" #include "chrome_frame/ready_mode/internal/ready_prompt_window.h" +#include "chrome_frame/ready_mode/internal/url_launcher.h" -ReadyPromptContent::ReadyPromptContent(ReadyModeState* ready_mode_state) - : ready_mode_state_(ready_mode_state) { +ReadyPromptContent::ReadyPromptContent(ReadyModeState* ready_mode_state, + UrlLauncher* url_launcher) + : ready_mode_state_(ready_mode_state), + url_launcher_(url_launcher) { } ReadyPromptContent::~ReadyPromptContent() { @@ -26,10 +26,11 @@ ReadyPromptContent::~ReadyPromptContent() { bool ReadyPromptContent::InstallInFrame(Frame* frame) { DCHECK(window_ == NULL); DCHECK(ready_mode_state_ != NULL); + DCHECK(url_launcher_ != NULL); - // The window owns itself upon call to Initialize. - ReadyPromptWindow* new_window_ = new ReadyPromptWindow(); - window_ = new_window_->Initialize(frame, ready_mode_state_.release()); + // Pass ownership of our ready_mode_state_ and url_launcher_ to the window. + window_ = ReadyPromptWindow::CreateInstance( + frame, ready_mode_state_.release(), url_launcher_.release()); return window_ != NULL; } diff --git a/chrome_frame/ready_mode/internal/ready_prompt_content.h b/chrome_frame/ready_mode/internal/ready_prompt_content.h index bb8692e..5a1f670 100644 --- a/chrome_frame/ready_mode/internal/ready_prompt_content.h +++ b/chrome_frame/ready_mode/internal/ready_prompt_content.h @@ -13,14 +13,18 @@ class ReadyModeState; class ReadyPromptWindow; +class UrlLauncher; // Encapsulates the Ready Mode prompt inviting users to permanently activate // Chrome Frame, temporarily disable Ready Mode, or permanently disable Ready // Mode. class ReadyPromptContent : public InfobarContent { public: - explicit ReadyPromptContent(ReadyModeState* ready_mode_state); - ~ReadyPromptContent(); + // Takes ownership of the ReadyModeState and UrlLauncher instances, which + // will be freed upon destruction of the ReadyPromptContent. + ReadyPromptContent(ReadyModeState* ready_mode_state, + UrlLauncher* url_launcher); + virtual ~ReadyPromptContent(); // InfobarContent implementation virtual bool InstallInFrame(Frame* frame); @@ -30,6 +34,7 @@ class ReadyPromptContent : public InfobarContent { private: base::WeakPtr<ReadyPromptWindow> window_; scoped_ptr<ReadyModeState> ready_mode_state_; + scoped_ptr<UrlLauncher> url_launcher_; DISALLOW_COPY_AND_ASSIGN(ReadyPromptContent); }; // class ReadyPromptContent diff --git a/chrome_frame/ready_mode/internal/ready_prompt_window.cc b/chrome_frame/ready_mode/internal/ready_prompt_window.cc index b05fbce..ddb51a9 100644 --- a/chrome_frame/ready_mode/internal/ready_prompt_window.cc +++ b/chrome_frame/ready_mode/internal/ready_prompt_window.cc @@ -4,33 +4,63 @@ #include "chrome_frame/ready_mode/internal/ready_prompt_window.h" +#include <atlctrls.h> +#include <Shellapi.h> // Must appear before atlctrlx.h + +// These seem to be required by atlctrlx? +template<class A> +A min(A const& a, A const& b) { return a < b ? a : b; } + +template<class A> +A max(A const& a, A const& b) { return a > b ? a : b; } + +#include <atlctrlx.h> + #include "base/compiler_specific.h" +#include "base/win/scoped_bstr.h" +#include "base/win/scoped_comptr.h" #include "chrome_frame/ready_mode/internal/ready_mode_state.h" +#include "chrome_frame/ready_mode/internal/url_launcher.h" +#include "chrome_frame/simple_resource_loader.h" +#include "grit/chromium_strings.h" -ReadyPromptWindow::ReadyPromptWindow() - : frame_(NULL), +ReadyPromptWindow::ReadyPromptWindow( + InfobarContent::Frame* frame, ReadyModeState* ready_mode_state, + UrlLauncher* url_launcher) + : frame_(frame), + ready_mode_state_(ready_mode_state), + url_launcher_(url_launcher), weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { } +ReadyPromptWindow::~ReadyPromptWindow() { +} -base::WeakPtr<ReadyPromptWindow> ReadyPromptWindow::Initialize( - InfobarContent::Frame* frame, ReadyModeState* ready_mode_state) { +base::WeakPtr<ReadyPromptWindow> ReadyPromptWindow::CreateInstance( + InfobarContent::Frame* frame, ReadyModeState* ready_mode_state, + UrlLauncher* url_launcher) { DCHECK(frame != NULL); - DCHECK(frame_ == NULL); DCHECK(ready_mode_state != NULL); - DCHECK(ready_mode_state_ == NULL); + DCHECK(url_launcher != NULL); - frame_ = frame; - ready_mode_state_.reset(ready_mode_state); + base::WeakPtr<ReadyPromptWindow> instance((new ReadyPromptWindow( + frame, ready_mode_state, url_launcher))->weak_ptr_factory_.GetWeakPtr()); - DCHECK(!IsWindow()); + DCHECK(!instance->IsWindow()); - if (Create(frame->GetFrameWindow()) == NULL) { + if (instance->Create(frame->GetFrameWindow()) == NULL) { DPLOG(ERROR) << "Failed to create HWND for ReadyPromptWindow."; - delete this; return base::WeakPtr<ReadyPromptWindow>(); } - return weak_ptr_factory_.GetWeakPtr(); + // Subclass the "Learn more." text to make it behave like a link. Clicks are + // routed to OnLearnMore(). + CWindow rte = instance->GetDlgItem(IDC_PROMPT_LINK); + instance->link_.reset(new CHyperLink()); + instance->link_->SubclassWindow(rte); + instance->link_->SetHyperLinkExtendedStyle(HLINK_NOTIFYBUTTON, + HLINK_NOTIFYBUTTON); + + return instance; } void ReadyPromptWindow::OnDestroy() { @@ -69,6 +99,14 @@ LRESULT ReadyPromptWindow::OnNo(WORD /*wNotifyCode*/, return 0; } +LRESULT ReadyPromptWindow::OnLearnMore(WORD /*wParam*/, + LPNMHDR /*lParam*/, + BOOL& /*bHandled*/) { + url_launcher_->LaunchUrl(SimpleResourceLoader::Get( + IDS_CHROME_FRAME_READY_MODE_LEARN_MORE_URL)); + return 0; +} + void ReadyPromptWindow::OnFinalMessage(HWND) { delete this; } diff --git a/chrome_frame/ready_mode/internal/ready_prompt_window.h b/chrome_frame/ready_mode/internal/ready_prompt_window.h index 2d931a3..5dc87ae 100644 --- a/chrome_frame/ready_mode/internal/ready_prompt_window.h +++ b/chrome_frame/ready_mode/internal/ready_prompt_window.h @@ -14,11 +14,17 @@ #include "base/weak_ptr.h" #include "base/scoped_ptr.h" +#include "base/win/scoped_comptr.h" #include "chrome_frame/infobars/infobar_content.h" #include "chrome_frame/resource.h" #include "grit/generated_resources.h" class ReadyModeState; +class UrlLauncher; + +namespace WTL { +class CHyperLink; +} // namespace WTL // Implements a dialog with text and buttons inviting the user to permanently // activate the product or temporarily/permanently disable Ready Mode. @@ -28,39 +34,49 @@ class ReadyPromptWindow public: enum { IDD = IDD_CHROME_FRAME_READY_PROMPT }; - ReadyPromptWindow(); - ~ReadyPromptWindow() {} - - // Initializes the dialog for display in the provided frame. The + // Creates and initializes a dialog for display in the provided frame. The // ReadyModeState will be invoked to capture the user's response, if any. + // The UrlLauncher may be used to launch a new tab containing a + // knowledge-base article about Ready Mode. // // Upon success, takes ownership of itself (to be deleted upon WM_DESTROY) and // returns a weak pointer to this dialog. Upon failure, returns a null weak // pointer and deletes self. // - // In either case, takes ownership of the ReadyModeState, but not the frame. - base::WeakPtr<ReadyPromptWindow> Initialize(InfobarContent::Frame* frame, - ReadyModeState* ready_mode_state); + // In either case, takes ownership of the ReadyModeState and UrlLauncher, but + // not the frame. + static base::WeakPtr<ReadyPromptWindow> CreateInstance( + InfobarContent::Frame* frame, + ReadyModeState* ready_mode_state, + UrlLauncher* url_launcher); BEGIN_MSG_MAP(InfobarWindow) MSG_WM_INITDIALOG(OnInitDialog) MSG_WM_DESTROY(OnDestroy) + NOTIFY_HANDLER(IDC_PROMPT_LINK, NM_CLICK, OnLearnMore) COMMAND_HANDLER(IDACTIVATE, BN_CLICKED, OnYes) - COMMAND_HANDLER(IDLATER, BN_CLICKED, OnRemindMeLater) COMMAND_HANDLER(IDNEVER, BN_CLICKED, OnNo) CHAIN_MSG_MAP(CDialogResize<ReadyPromptWindow>) END_MSG_MAP() BEGIN_DLGRESIZE_MAP(InfobarWindow) DLGRESIZE_CONTROL(IDACTIVATE, DLSZ_CENTER_Y | DLSZ_MOVE_X) - DLGRESIZE_CONTROL(IDLATER, DLSZ_CENTER_Y | DLSZ_MOVE_X) DLGRESIZE_CONTROL(IDNEVER, DLSZ_CENTER_Y | DLSZ_MOVE_X) DLGRESIZE_CONTROL(IDC_PROMPT_MESSAGE, DLSZ_SIZE_Y | DLSZ_SIZE_X) + DLGRESIZE_CONTROL(IDC_PROMPT_LINK, DLSZ_CENTER_Y | DLSZ_MOVE_X) END_DLGRESIZE_MAP() virtual void OnFinalMessage(HWND); private: + // Call CreateInstance() to get an initialized ReadyPromptWindow. + ReadyPromptWindow(InfobarContent::Frame* frame, + ReadyModeState* ready_mode_state, + UrlLauncher* url_launcher); + + // The ReadyPromptWindow manages its own destruction. + virtual ~ReadyPromptWindow(); + // Event handlers. void OnDestroy(); BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam); @@ -72,6 +88,7 @@ class ReadyPromptWindow WORD wID, HWND hWndCtl, BOOL& bHandled); + LRESULT OnLearnMore(WORD wParam, LPNMHDR lParam, BOOL& bHandled); // NOLINT LRESULT OnNo(WORD wNotifyCode, WORD wID, HWND hWndCtl, @@ -79,6 +96,8 @@ class ReadyPromptWindow InfobarContent::Frame* frame_; // Not owned by this instance scoped_ptr<ReadyModeState> ready_mode_state_; + scoped_ptr<WTL::CHyperLink> link_; + scoped_ptr<UrlLauncher> url_launcher_; base::WeakPtrFactory<ReadyPromptWindow> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ReadyPromptWindow); diff --git a/chrome_frame/ready_mode/internal/url_launcher.h b/chrome_frame/ready_mode/internal/url_launcher.h new file mode 100644 index 0000000..ea3711c --- /dev/null +++ b/chrome_frame/ready_mode/internal/url_launcher.h @@ -0,0 +1,20 @@ +// 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_FRAME_READY_MODE_INTERNAL_URL_LAUNCHER_H_ +#define CHROME_FRAME_READY_MODE_INTERNAL_URL_LAUNCHER_H_ +#pragma once + +// Implements the launching of a new browser window/tab. The +// ReadyPromptContent invokes this, in response to user action, to display +// documentation about Ready Mode. +class UrlLauncher { + public: + virtual ~UrlLauncher() {} + + // Displays the specified URL in a new window or tab. + virtual void LaunchUrl(const std::wstring& url) = 0; +}; // class UrlHelper + +#endif // CHROME_FRAME_READY_MODE_INTERNAL_URL_LAUNCHER_H_ diff --git a/chrome_frame/ready_mode/ready_mode.cc b/chrome_frame/ready_mode/ready_mode.cc index 82b5d23..51df76f 100644 --- a/chrome_frame/ready_mode/ready_mode.cc +++ b/chrome_frame/ready_mode/ready_mode.cc @@ -21,6 +21,7 @@ #include "chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.h" #include "chrome_frame/ready_mode/internal/ready_prompt_content.h" #include "chrome_frame/ready_mode/internal/registry_ready_mode_state.h" +#include "chrome_frame/ready_mode/internal/url_launcher.h" #include "chrome_frame/utils.h" namespace { @@ -90,6 +91,33 @@ class BrowserObserver : public ReadyModeWebBrowserAdapter::Observer { DISALLOW_COPY_AND_ASSIGN(BrowserObserver); }; // class BrowserObserver +// Implements launching of a URL in an instance of IWebBrowser2. +class UrlLauncherImpl : public UrlLauncher { + public: + explicit UrlLauncherImpl(IWebBrowser2* web_browser); + + // UrlLauncher implementation + void LaunchUrl(const std::wstring& url); + + private: + base::win::ScopedComPtr<IWebBrowser2> web_browser_; +}; // class UrlLaucherImpl + +UrlLauncherImpl::UrlLauncherImpl(IWebBrowser2* web_browser) { + DCHECK(web_browser); + web_browser_ = web_browser; +} + +void UrlLauncherImpl::LaunchUrl(const std::wstring& url) { + VARIANT flags = { VT_I4 }; + V_I4(&flags) = navOpenInNewWindow; + base::win::ScopedBstr location(url.c_str()); + + HRESULT hr = web_browser_->Navigate(location, &flags, NULL, NULL, NULL); + DLOG_IF(ERROR, FAILED(hr)) << "Failed to invoke Navigate on IWebBrowser2. " + << "Error: " << hr; +} + StateObserver::StateObserver( const base::WeakPtr<BrowserObserver>& ready_mode_ui) : ready_mode_ui_(ready_mode_ui) { @@ -200,9 +228,12 @@ void BrowserObserver::ShowPrompt() { base::TimeDelta::FromMinutes(kTemporaryDeclineDurationMinutes), ready_mode_state_observer.release())); + // Owned by infobar_content + scoped_ptr<UrlLauncher> url_launcher(new UrlLauncherImpl(web_browser_)); + // Owned by infobar_manager - scoped_ptr<InfobarContent> infobar_content( - new ReadyPromptContent(ready_mode_state.release())); + scoped_ptr<InfobarContent> infobar_content(new ReadyPromptContent( + ready_mode_state.release(), url_launcher.release())); infobar_manager->Show(infobar_content.release(), TOP_INFOBAR); } diff --git a/chrome_frame/test/ready_mode_unittest.cc b/chrome_frame/test/ready_mode_unittest.cc index a462ff2..e404269b 100644 --- a/chrome_frame/test/ready_mode_unittest.cc +++ b/chrome_frame/test/ready_mode_unittest.cc @@ -18,6 +18,7 @@ #include "chrome_frame/ready_mode/internal/ready_prompt_content.h" #include "chrome_frame/ready_mode/internal/ready_prompt_window.h" #include "chrome_frame/ready_mode/internal/registry_ready_mode_state.h" +#include "chrome_frame/ready_mode/internal/url_launcher.h" #include "chrome_frame/simple_resource_loader.h" #include "chrome_frame/test/chrome_frame_test_utils.h" @@ -97,6 +98,12 @@ class MockReadyModeState : public ReadyModeState { MOCK_METHOD0(AcceptChromeFrame, void(void)); }; // class MockReadyModeState +class MockUrlLauncher : public UrlLauncher { + public: + // UrlLauncher implementation + MOCK_METHOD1(LaunchUrl, void(const std::wstring& url)); +}; // class MockUrlLauncher + } // namespace class ReadyPromptTest : public testing::Test { @@ -126,8 +133,10 @@ class ReadyPromptWindowTest : public ReadyPromptTest { // owned by ReadyPromptWindow state_ = new MockReadyModeState(); - ready_prompt_window_ = (new ReadyPromptWindow())->Initialize(&frame_, - state_); + url_launcher_ = new MockUrlLauncher(); + + ready_prompt_window_ = ReadyPromptWindow::CreateInstance( + &frame_, state_, url_launcher_); ASSERT_TRUE(ready_prompt_window_ != NULL); RECT position = {0, 0, 800, 39}; @@ -137,6 +146,7 @@ class ReadyPromptWindowTest : public ReadyPromptTest { protected: MockReadyModeState* state_; + MockUrlLauncher* url_launcher_; base::WeakPtr<ReadyPromptWindow> ready_prompt_window_; }; // class ReadyPromptWindowTest @@ -212,7 +222,10 @@ class ReadyPromptWindowButtonTest : public ReadyPromptWindowTest { TEST_F(ReadyPromptTest, ReadyPromptContentTest) { // owned by ReadyPromptContent MockReadyModeState* state = new MockReadyModeState(); - scoped_ptr<ReadyPromptContent> content_(new ReadyPromptContent(state)); + MockUrlLauncher* url_launcher = new MockUrlLauncher(); + + scoped_ptr<ReadyPromptContent> content_(new ReadyPromptContent(state, + url_launcher)); content_->InstallInFrame(&frame_); @@ -255,21 +268,15 @@ TEST_F(ReadyPromptWindowTest, Destroy) { ready_prompt_window_->DestroyWindow(); } -TEST_F(ReadyPromptWindowButtonTest, ClickYes) { +TEST_F(ReadyPromptWindowButtonTest, ClickEnable) { EXPECT_CALL(*state_, AcceptChromeFrame()); - ASSERT_TRUE(ClickOnCaption(L"&Yes")); - RunUntilCloseInfobar(); -} - -TEST_F(ReadyPromptWindowButtonTest, ClickRemindMeLater) { - EXPECT_CALL(*state_, TemporarilyDeclineChromeFrame()); - ASSERT_TRUE(ClickOnCaption(L"Remind me &Later")); + ASSERT_TRUE(ClickOnCaption(L"Enable")); RunUntilCloseInfobar(); } -TEST_F(ReadyPromptWindowButtonTest, ClickNo) { +TEST_F(ReadyPromptWindowButtonTest, ClickIgnore) { EXPECT_CALL(*state_, PermanentlyDeclineChromeFrame()); - ASSERT_TRUE(ClickOnCaption(L"&No")); + ASSERT_TRUE(ClickOnCaption(L"Ignore")); RunUntilCloseInfobar(); } |