diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-14 04:28:34 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-14 04:28:34 +0000 |
commit | dbd4b1dc9829c4afa9d59a7121d8df1f57f50b98 (patch) | |
tree | 3ede245f81fe1ebbd0958f8cc47a762830412ac5 | |
parent | c004d650005cf121332b36c4707dbe67afda53a0 (diff) | |
download | chromium_src-dbd4b1dc9829c4afa9d59a7121d8df1f57f50b98.zip chromium_src-dbd4b1dc9829c4afa9d59a7121d8df1f57f50b98.tar.gz chromium_src-dbd4b1dc9829c4afa9d59a7121d8df1f57f50b98.tar.bz2 |
Refactor AutofillPopupView and friends
Before:
AutofillPopupViewViews extends AutofillPopupView
AutofillExternalDelegateViews extends AutofillExternalDelegate, and owns AutofillPopupViewViews
After:
AutofillPopupController owns AutofillPopupViewViews which implements AutofillPopupView interface
AutofillExternalDelegate implements AutofillPopupDelegate, and creates / interacts with AutofillPopupController (no platform subclasses for AutofillExternalDelegate)
no dependency of AutofillPopupView and subclasses on content/
BUG=164966
Review URL: https://codereview.chromium.org/11446077
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173084 0039d316-1c4b-4281-b951-d872f2087c98
38 files changed, 1272 insertions, 1587 deletions
diff --git a/chrome/browser/autofill/autofill_external_delegate.cc b/chrome/browser/autofill/autofill_external_delegate.cc index 03a2e20..4afc3d6 100644 --- a/chrome/browser/autofill/autofill_external_delegate.cc +++ b/chrome/browser/autofill/autofill_external_delegate.cc @@ -6,6 +6,7 @@ #include "chrome/browser/autofill/autocomplete_history_manager.h" #include "chrome/browser/autofill/autofill_external_delegate.h" #include "chrome/browser/autofill/autofill_manager.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" #include "chrome/common/autofill_messages.h" #include "chrome/common/chrome_constants.h" #include "content/public/browser/navigation_controller.h" @@ -14,28 +15,42 @@ #include "content/public/browser/notification_types.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_view.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h" #include "ui/base/l10n/l10n_util.h" +#if defined(OS_ANDROID) +#include "content/public/browser/android/content_view_core.h" +#endif + using content::RenderViewHost; using WebKit::WebAutofillClient; DEFINE_WEB_CONTENTS_USER_DATA_KEY(AutofillExternalDelegate) -AutofillExternalDelegate::~AutofillExternalDelegate() {} +void AutofillExternalDelegate::CreateForWebContentsAndManager( + content::WebContents* web_contents, + AutofillManager* autofill_manager) { + if (FromWebContents(web_contents)) + return; + + web_contents->SetUserData( + UserDataKey(), + new AutofillExternalDelegate(web_contents, autofill_manager)); +} AutofillExternalDelegate::AutofillExternalDelegate( content::WebContents* web_contents, AutofillManager* autofill_manager) : web_contents_(web_contents), autofill_manager_(autofill_manager), + controller_(NULL), password_autofill_manager_(web_contents), autofill_query_id_(0), display_warning_if_disabled_(false), - has_shown_autofill_popup_for_current_edit_(false), - popup_visible_(false) { + has_shown_autofill_popup_for_current_edit_(false) { registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED, content::Source<content::WebContents>(web_contents)); @@ -48,6 +63,11 @@ AutofillExternalDelegate::AutofillExternalDelegate( } } +AutofillExternalDelegate::~AutofillExternalDelegate() { + if (controller_) + controller_->DelegateDestroyed(); +} + void AutofillExternalDelegate::SelectAutofillSuggestionAtIndex(int unique_id) { ClearPreviewedForm(); @@ -59,14 +79,14 @@ void AutofillExternalDelegate::SelectAutofillSuggestionAtIndex(int unique_id) { void AutofillExternalDelegate::OnQuery(int query_id, const FormData& form, const FormFieldData& field, - const gfx::Rect& bounds, + const gfx::Rect& element_bounds, bool display_warning_if_disabled) { autofill_query_form_ = form; autofill_query_field_ = field; display_warning_if_disabled_ = display_warning_if_disabled; autofill_query_id_ = query_id; - CreatePopupForElement(bounds); + EnsurePopupForElement(element_bounds); } void AutofillExternalDelegate::OnSuggestionsReturned( @@ -122,7 +142,6 @@ void AutofillExternalDelegate::OnSuggestionsReturned( // Send to display. if (autofill_query_field_.is_focusable) { - popup_visible_ = true; ApplyAutofillSuggestions(values, labels, icons, ids); if (autofill_manager_) { @@ -136,11 +155,9 @@ void AutofillExternalDelegate::OnSuggestionsReturned( void AutofillExternalDelegate::OnShowPasswordSuggestions( const std::vector<string16>& suggestions, const FormFieldData& field, - const gfx::Rect& bounds) { - if (!popup_visible_) { - autofill_query_field_ = field; - CreatePopupForElement(bounds); - } + const gfx::Rect& element_bounds) { + autofill_query_field_ = field; + EnsurePopupForElement(element_bounds); if (suggestions.empty()) { HideAutofillPopup(); @@ -150,24 +167,44 @@ void AutofillExternalDelegate::OnShowPasswordSuggestions( std::vector<string16> empty(suggestions.size()); std::vector<int> password_ids(suggestions.size(), WebAutofillClient::MenuItemIDPasswordEntry); - popup_visible_ = true; ApplyAutofillSuggestions(suggestions, empty, empty, password_ids); } +void AutofillExternalDelegate::EnsurePopupForElement( + const gfx::Rect& element_bounds) { + if (controller_) + return; + + // |controller_| owns itself. + controller_ = new AutofillPopupControllerImpl( + this, + // web_contents() may be NULL during testing. + web_contents() ? web_contents()->GetView()->GetContentNativeView() : NULL, + element_bounds); +} + +void AutofillExternalDelegate::ApplyAutofillSuggestions( + const std::vector<string16>& autofill_values, + const std::vector<string16>& autofill_labels, + const std::vector<string16>& autofill_icons, + const std::vector<int>& autofill_unique_ids) { + controller_->Show(autofill_values, + autofill_labels, + autofill_icons, + autofill_unique_ids); + + web_contents()->GetRenderViewHost()->AddKeyboardListener(controller_); +} + void AutofillExternalDelegate::SetCurrentDataListValues( const std::vector<string16>& data_list_values, const std::vector<string16>& data_list_labels, const std::vector<string16>& data_list_icons, const std::vector<int>& data_list_unique_ids) { - // TODO(csharp): Modify the code to allow the data list values to change - // even if the popup is visible. - // http://crbug.com/131003 - if (!popup_visible_) { - data_list_values_ = data_list_values; - data_list_labels_ = data_list_labels; - data_list_icons_ = data_list_icons; - data_list_unique_ids_ = data_list_unique_ids; - } + data_list_values_ = data_list_values; + data_list_labels_ = data_list_labels; + data_list_icons_ = data_list_icons; + data_list_unique_ids_ = data_list_unique_ids; } void AutofillExternalDelegate::RemoveAutocompleteEntry(const string16& value) { @@ -182,14 +219,13 @@ void AutofillExternalDelegate::RemoveAutofillProfileOrCreditCard( autofill_manager_->RemoveAutofillProfileOrCreditCard(unique_id); } - void AutofillExternalDelegate::DidEndTextFieldEditing() { HideAutofillPopup(); has_shown_autofill_popup_for_current_edit_ = false; } -bool AutofillExternalDelegate::DidAcceptAutofillSuggestions( +bool AutofillExternalDelegate::DidAcceptAutofillSuggestion( const string16& value, int unique_id, unsigned index) { @@ -236,14 +272,16 @@ void AutofillExternalDelegate::ClearPreviewedForm() { } } -void AutofillExternalDelegate::HideAutofillPopup() { - if (!popup_visible_) - return; - - popup_visible_ = false; +void AutofillExternalDelegate::ControllerDestroyed() { + web_contents()->GetRenderViewHost()->RemoveKeyboardListener(controller_); + controller_ = NULL; +} - ClearPreviewedForm(); - HideAutofillPopupInternal(); +void AutofillExternalDelegate::HideAutofillPopup() { + if (controller_) { + ClearPreviewedForm(); + controller_->Hide(); + } } void AutofillExternalDelegate::Reset() { @@ -255,7 +293,7 @@ void AutofillExternalDelegate::Reset() { void AutofillExternalDelegate::AddPasswordFormMapping( const FormFieldData& form, const PasswordFormFillData& fill_data) { - password_autofill_manager_.AddPasswordFormMapping(form, fill_data); + password_autofill_manager_.AddPasswordFormMapping(form, fill_data); } void AutofillExternalDelegate::FillAutofillFormData(int unique_id, @@ -383,12 +421,3 @@ void AutofillExternalDelegate::Observe( } - -#if defined(OS_MACOSX) - -void AutofillExternalDelegate::CreateForWebContentsAndManager( - content::WebContents* web_contents, - AutofillManager* autofill_manager) { -} - -#endif diff --git a/chrome/browser/autofill/autofill_external_delegate.h b/chrome/browser/autofill/autofill_external_delegate.h index 13692d1..2f278e5 100644 --- a/chrome/browser/autofill/autofill_external_delegate.h +++ b/chrome/browser/autofill/autofill_external_delegate.h @@ -9,16 +9,18 @@ #include "base/compiler_specific.h" #include "base/string16.h" +#include "chrome/browser/autofill/autofill_popup_delegate.h" #include "chrome/browser/autofill/password_autofill_manager.h" #include "chrome/common/form_data.h" #include "chrome/common/form_field_data.h" #include "chrome/common/password_form_fill_data.h" -#include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_user_data.h" #include "ui/gfx/rect.h" class AutofillManager; +class AutofillPopupControllerImpl; namespace gfx { class Rect; @@ -32,25 +34,27 @@ class WebContents; // Once Autofill is moved out of WebKit this class should be the only home for // this logic. See http://crbug.com/51644 -// Delegate for external processing of Autocomplete and Autofill -// display and selection. +// Delegate for in-browser Autocomplete and Autofill display and selection. class AutofillExternalDelegate : public content::WebContentsUserData<AutofillExternalDelegate>, - public content::NotificationObserver { + public content::NotificationObserver, + public AutofillPopupDelegate { public: // Creates an AutofillExternalDelegate and attaches it to the specified // contents; the second argument is an AutofillManager managing Autofill for // that WebContents. - // - // This call is implemented per-platform. static void CreateForWebContentsAndManager(content::WebContents* web_contents, AutofillManager* autofill_manager); - virtual ~AutofillExternalDelegate(); - - // When using an external Autofill delegate. Allows Chrome to tell - // WebKit which Autofill selection has been chosen. - virtual void SelectAutofillSuggestionAtIndex(int unique_id); + // AutofillPopupDelegate implementation. + virtual void SelectAutofillSuggestionAtIndex(int unique_id) OVERRIDE; + virtual bool DidAcceptAutofillSuggestion(const string16& value, + int unique_id, + unsigned index) OVERRIDE; + virtual void ClearPreviewedForm() OVERRIDE; + virtual void RemoveAutocompleteEntry(const string16& value) OVERRIDE; + virtual void RemoveAutofillProfileOrCreditCard(int unique_id) OVERRIDE; + virtual void ControllerDestroyed() OVERRIDE; // Records and associates a query_id with web form data. Called // when the renderer posts an Autofill query to the browser. |bounds| @@ -62,7 +66,7 @@ class AutofillExternalDelegate virtual void OnQuery(int query_id, const FormData& form, const FormFieldData& field, - const gfx::Rect& bounds, + const gfx::Rect& element_bounds, bool display_warning_if_disabled); // Records query results and correctly formats them before sending them off @@ -85,28 +89,10 @@ class AutofillExternalDelegate const std::vector<string16>& autofill_icons, const std::vector<int>& autofill_unique_ids); - // Remove the given Autocomplete entry from the DB. - virtual void RemoveAutocompleteEntry(const string16& value); - - // Remove the given Autofill profile or credit credit. - virtual void RemoveAutofillProfileOrCreditCard(int unique_id); - // Inform the delegate that the text field editing has ended. This is // used to help record the metrics of when a new popup is shown. void DidEndTextFieldEditing(); - // Inform the delegate that an Autofill suggestion has been chosen. Returns - // true if the suggestion was selected. - bool DidAcceptAutofillSuggestions(const string16& value, - int unique_id, - unsigned index); - - // Informs the delegate that the Autofill previewed form should be cleared. - virtual void ClearPreviewedForm(); - - // Hide the Autofill poup. - virtual void HideAutofillPopup(); - // Returns the delegate to its starting state by removing any page specific // values or settings. void Reset(); @@ -116,10 +102,13 @@ class AutofillExternalDelegate const FormFieldData& form, const PasswordFormFillData& fill_data); + virtual void HideAutofillPopup(); + protected: friend class content::WebContentsUserData<AutofillExternalDelegate>; AutofillExternalDelegate(content::WebContents* web_contents, AutofillManager* autofill_manager); + virtual ~AutofillExternalDelegate(); // Displays the Autofill results to the user with an external Autofill popup // that lives completely in the browser. The suggestions have been correctly @@ -128,22 +117,15 @@ class AutofillExternalDelegate const std::vector<string16>& autofill_values, const std::vector<string16>& autofill_labels, const std::vector<string16>& autofill_icons, - const std::vector<int>& autofill_unique_ids) = 0; - - // Handle platform-dependent hiding. - virtual void HideAutofillPopupInternal() = 0; + const std::vector<int>& autofill_unique_ids); - // Create and position the popup given the bounds of the element it is - // popping up for. - virtual void CreatePopupForElement(const gfx::Rect& element_bounds) = 0; + // Create the popup if it doesn't already exist. |element_bounds| is the + // bounding rect for the element it is popping up for. + virtual void EnsurePopupForElement(const gfx::Rect& element_bounds); - // Return the web_contents associated with this delegate. content::WebContents* web_contents() { return web_contents_; } - // Return the bounds of the field currently selected. - const gfx::Rect& field_bounds() { return field_bounds_; } - - bool popup_visible() const { return popup_visible_; } + AutofillPopupControllerImpl* controller() { return controller_; } private: // Fills the form with the Autofill data corresponding to |unique_id|. @@ -178,8 +160,10 @@ class AutofillExternalDelegate const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; + // The web_contents associated with this delegate. content::WebContents* web_contents_; // weak; owns me. AutofillManager* autofill_manager_; // weak. + AutofillPopupControllerImpl* controller_; // weak. // Password Autofill manager, handles all password-related Autofilling. PasswordAutofillManager password_autofill_manager_; @@ -202,12 +186,6 @@ class AutofillExternalDelegate // currently editing? Used to keep track of state for metrics logging. bool has_shown_autofill_popup_for_current_edit_; - // Used to indicate if a popup is currently being shown or not. - bool popup_visible_; - - // The bounds of the field currently selected. - gfx::Rect field_bounds_; - // The current data list values. std::vector<string16> data_list_values_; std::vector<string16> data_list_labels_; diff --git a/chrome/browser/autofill/autofill_popup_view_browsertest.cc b/chrome/browser/autofill/autofill_external_delegate_browsertest.cc index 3d23608..2cef3e0 100644 --- a/chrome/browser/autofill/autofill_popup_view_browsertest.cc +++ b/chrome/browser/autofill/autofill_external_delegate_browsertest.cc @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/autofill/autofill_popup_view.h" - #include "base/memory/scoped_ptr.h" #include "chrome/browser/autofill/autofill_manager.h" #include "chrome/browser/autofill/test_autofill_external_delegate.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" +#include "chrome/browser/ui/autofill/autofill_popup_view.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/common/url_constants.h" @@ -27,13 +27,12 @@ using testing::_; namespace { -class MockAutofillExternalDelegate : - public autofill::TestAutofillExternalDelegate { +class MockAutofillExternalDelegate : public AutofillExternalDelegate { public: - explicit MockAutofillExternalDelegate(content::WebContents* web_contents) : - TestAutofillExternalDelegate( - web_contents, - AutofillManager::FromWebContents(web_contents)) {} + explicit MockAutofillExternalDelegate(content::WebContents* web_contents) + : AutofillExternalDelegate( + web_contents, + AutofillManager::FromWebContents(web_contents)) {} ~MockAutofillExternalDelegate() {} virtual void SelectAutofillSuggestionAtIndex(int unique_id) @@ -41,57 +40,64 @@ class MockAutofillExternalDelegate : virtual void ClearPreviewedForm() OVERRIDE {} - MOCK_METHOD0(HideAutofillPopupInternal, void()); -}; - -class TestAutofillPopupView : public AutofillPopupView { - public: - TestAutofillPopupView( - content::WebContents* web_contents, - AutofillExternalDelegate* autofill_external_delegate) - : AutofillPopupView(web_contents, - autofill_external_delegate, - gfx::Rect()) {} - virtual ~TestAutofillPopupView() {} - - MOCK_METHOD0(Hide, void()); - - protected: - virtual void ShowInternal() OVERRIDE {} - - virtual void InvalidateRow(size_t row) OVERRIDE {} + AutofillPopupControllerImpl* GetController() { + return controller(); + } - virtual void UpdateBoundsAndRedrawPopupInternal() OVERRIDE {} + MOCK_METHOD0(HideAutofillPopup, void()); }; } // namespace -class AutofillPopupViewBrowserTest : public InProcessBrowserTest { +class AutofillExternalDelegateBrowserTest + : public InProcessBrowserTest, + public content::WebContentsObserver { public: - AutofillPopupViewBrowserTest() {} - virtual ~AutofillPopupViewBrowserTest() {} + AutofillExternalDelegateBrowserTest() {} + virtual ~AutofillExternalDelegateBrowserTest() {} virtual void SetUpOnMainThread() OVERRIDE { web_contents_ = chrome::GetActiveWebContents(browser()); ASSERT_TRUE(web_contents_ != NULL); + Observe(web_contents_); - autofill_external_delegate_.reset(new MockAutofillExternalDelegate( - web_contents_)); - autofill_popup_view_.reset(new TestAutofillPopupView( - web_contents_, - autofill_external_delegate_.get())); + autofill_external_delegate_.reset( + new MockAutofillExternalDelegate(web_contents_)); + } + + // Normally the WebContents will automatically delete the delegate, but here + // the delegate is owned by this test, so we have to manually destroy. + virtual void WebContentsDestroyed(content::WebContents* web_contents) + OVERRIDE { + DCHECK_EQ(web_contents_, web_contents); + autofill_external_delegate_.reset(); } protected: content::WebContents* web_contents_; - scoped_ptr<TestAutofillPopupView> autofill_popup_view_; scoped_ptr<MockAutofillExternalDelegate> autofill_external_delegate_; }; -IN_PROC_BROWSER_TEST_F(AutofillPopupViewBrowserTest, - SwitchTabAndHideAutofillPopup) { +#if defined(OS_MACOSX) +// TODO(estade): Mac doesn't have an implementation for the view yet, so these +// are disabled. +#define MAYBE_SwitchTabAndHideAutofillPopup \ + DISABLED_SwitchTabAndHideAutofillPopup +#define MAYBE_TestPageNavigationHidingAutofillPopup \ + DISABLED_TestPageNavigationHidingAutofillPopup +#define MAYBE_CloseWidgetAndNoLeaking \ + DISABLED_CloseWidgetAndNoLeaking +#else +#define MAYBE_SwitchTabAndHideAutofillPopup SwitchTabAndHideAutofillPopup +#define MAYBE_TestPageNavigationHidingAutofillPopup \ + TestPageNavigationHidingAutofillPopup +#define MAYBE_CloseWidgetAndNoLeaking CloseWidgetAndNoLeaking +#endif + +IN_PROC_BROWSER_TEST_F(AutofillExternalDelegateBrowserTest, + MAYBE_SwitchTabAndHideAutofillPopup) { EXPECT_CALL(*autofill_external_delegate_, - HideAutofillPopupInternal()).Times(AtLeast(1)); + HideAutofillPopup()).Times(AtLeast(1)); autofill::GenerateTestAutofillPopup(autofill_external_delegate_.get()); @@ -105,10 +111,10 @@ IN_PROC_BROWSER_TEST_F(AutofillPopupViewBrowserTest, // The mock verifies that the call was made. } -IN_PROC_BROWSER_TEST_F(AutofillPopupViewBrowserTest, - TestPageNavigationHidingAutofillPopup) { +IN_PROC_BROWSER_TEST_F(AutofillExternalDelegateBrowserTest, + MAYBE_TestPageNavigationHidingAutofillPopup) { EXPECT_CALL(*autofill_external_delegate_, - HideAutofillPopupInternal()).Times(AtLeast(1)); + HideAutofillPopup()).Times(AtLeast(1)); autofill::GenerateTestAutofillPopup(autofill_external_delegate_.get()); @@ -126,3 +132,15 @@ IN_PROC_BROWSER_TEST_F(AutofillPopupViewBrowserTest, // The mock verifies that the call was made. } + +IN_PROC_BROWSER_TEST_F(AutofillExternalDelegateBrowserTest, + MAYBE_CloseWidgetAndNoLeaking) { + EXPECT_CALL(*autofill_external_delegate_, + HideAutofillPopup()).Times(AtLeast(1)); + + autofill::GenerateTestAutofillPopup(autofill_external_delegate_.get()); + + // Delete the view from under the delegate to ensure that the + // delegate and the controller can handle the popup getting deleted elsewhere. + autofill_external_delegate_->GetController()->view()->Hide(); +} diff --git a/chrome/browser/autofill/autofill_external_delegate_unittest.cc b/chrome/browser/autofill/autofill_external_delegate_unittest.cc index a1b834a..0b6f3fd 100644 --- a/chrome/browser/autofill/autofill_external_delegate_unittest.cc +++ b/chrome/browser/autofill/autofill_external_delegate_unittest.cc @@ -40,10 +40,6 @@ class MockAutofillExternalDelegate : : TestAutofillExternalDelegate(web_contents, autofill_manger) {} ~MockAutofillExternalDelegate() {} - bool popup_visible() { - return autofill::TestAutofillExternalDelegate::popup_visible(); - } - MOCK_METHOD4(ApplyAutofillSuggestions, void( const std::vector<string16>& autofill_values, const std::vector<string16>& autofill_labels, @@ -52,10 +48,9 @@ class MockAutofillExternalDelegate : MOCK_METHOD0(ClearPreviewedForm, void()); - MOCK_METHOD1(CreatePopupForElement, void(const gfx::Rect& element_bounds)); + MOCK_METHOD1(EnsurePopupForElement, void(const gfx::Rect& element_bounds)); - private: - virtual void HideAutofillPopupInternal() {}; + MOCK_METHOD0(HideAutofillPopup, void()); }; class MockAutofillManager : public AutofillManager { @@ -96,12 +91,13 @@ class AutofillExternalDelegateUnitTest field.should_autocomplete = true; const gfx::Rect element_bounds; - EXPECT_CALL(*external_delegate_, CreatePopupForElement(element_bounds)); + EXPECT_CALL(*external_delegate_, EnsurePopupForElement(element_bounds)); external_delegate_->OnQuery(query_id, form, field, element_bounds, false); } scoped_refptr<MockAutofillManager> autofill_manager_; - scoped_ptr<MockAutofillExternalDelegate> external_delegate_; + scoped_ptr<testing::NiceMock<MockAutofillExternalDelegate> > + external_delegate_; private: virtual void SetUp() OVERRIDE { @@ -110,9 +106,10 @@ class AutofillExternalDelegateUnitTest autofill_manager_ = new MockAutofillManager( web_contents(), TabAutofillManagerDelegate::FromWebContents(web_contents())); - external_delegate_.reset(new MockAutofillExternalDelegate( - web_contents(), - autofill_manager_)); + external_delegate_.reset( + new testing::NiceMock<MockAutofillExternalDelegate>( + web_contents(), + autofill_manager_)); } virtual void TearDown() OVERRIDE { @@ -151,19 +148,16 @@ TEST_F(AutofillExternalDelegateUnitTest, TestExternalDelegateVirtualCalls) { autofill_item, autofill_item, autofill_ids); - EXPECT_TRUE(external_delegate_->popup_visible()); - - // Called when hiding the popup. - EXPECT_CALL(*external_delegate_, ClearPreviewedForm()); // Called by DidAutofillSuggestions, add expectation to remove warning. EXPECT_CALL(*autofill_manager_, OnFillAutofillFormData(_, _, _, _)); + EXPECT_CALL(*external_delegate_, HideAutofillPopup()); + // This should trigger a call to hide the popup since // we've selected an option. - external_delegate_->DidAcceptAutofillSuggestions(autofill_item[0], - autofill_ids[0], 0); - EXPECT_FALSE(external_delegate_->popup_visible()); + external_delegate_->DidAcceptAutofillSuggestion(autofill_item[0], + autofill_ids[0], 0); } // Test that data list elements for a node will appear in the Autofill popup. @@ -231,7 +225,7 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateInvalidUniqueId) { // Ensure it doesn't try to fill the form in with the negative id. EXPECT_CALL(*autofill_manager_, OnFillAutofillFormData(_, _, _, _)).Times(0); - external_delegate_->DidAcceptAutofillSuggestions(string16(), -1, 0); + external_delegate_->DidAcceptAutofillSuggestion(string16(), -1, 0); } // Test that the ClearPreview IPC is only sent the form was being previewed @@ -254,18 +248,14 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateClearPreviewedForm) { // Test that the popup is hidden once we are done editing the autofill field. TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateHidePopupAfterEditing) { - EXPECT_CALL(*external_delegate_, CreatePopupForElement(_)); + EXPECT_CALL(*external_delegate_, EnsurePopupForElement(_)); EXPECT_CALL(*external_delegate_, ApplyAutofillSuggestions(_, _, _, _)); autofill::GenerateTestAutofillPopup(external_delegate_.get()); - EXPECT_TRUE(external_delegate_->popup_visible()); - // Called when hiding the popup. - EXPECT_CALL(*external_delegate_, ClearPreviewedForm()); + EXPECT_CALL(*external_delegate_, HideAutofillPopup()); external_delegate_->DidEndTextFieldEditing(); - - EXPECT_FALSE(external_delegate_->popup_visible()); } // Test that the popup is marked as visible after recieving password @@ -279,7 +269,7 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegatePasswordSuggestions) { field.should_autocomplete = true; const gfx::Rect element_bounds; - EXPECT_CALL(*external_delegate_, CreatePopupForElement(element_bounds)); + EXPECT_CALL(*external_delegate_, EnsurePopupForElement(element_bounds)); // The enums must be cast to ints to prevent compile errors on linux_rel. EXPECT_CALL(*external_delegate_, @@ -290,19 +280,16 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegatePasswordSuggestions) { external_delegate_->OnShowPasswordSuggestions(suggestions, field, element_bounds); - EXPECT_TRUE(external_delegate_->popup_visible()); // Called by DidAutofillSuggestions, add expectation to remove warning. EXPECT_CALL(*autofill_manager_, OnFillAutofillFormData(_, _, _, _)); - // Called when hiding the popup. - EXPECT_CALL(*external_delegate_, ClearPreviewedForm()); + EXPECT_CALL(*external_delegate_, HideAutofillPopup()); // This should trigger a call to hide the popup since // we've selected an option. - external_delegate_->DidAcceptAutofillSuggestions( + external_delegate_->DidAcceptAutofillSuggestion( suggestions[0], WebAutofillClient::MenuItemIDPasswordEntry, 0); - EXPECT_FALSE(external_delegate_->popup_visible()); } diff --git a/chrome/browser/autofill/autofill_popup_delegate.h b/chrome/browser/autofill/autofill_popup_delegate.h new file mode 100644 index 0000000..6411766 --- /dev/null +++ b/chrome/browser/autofill/autofill_popup_delegate.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 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_AUTOFILL_AUTOFILL_POPUP_DELEGATE_H_ +#define CHROME_BROWSER_AUTOFILL_AUTOFILL_POPUP_DELEGATE_H_ + +#include "base/string16.h" + +// An interface for interaction with AutofillPopupController. Will be notified +// of events by the controller. +class AutofillPopupDelegate { + public: + // Called when the autofill suggestion indicated by |unique_id| has been + // temporarily selected (e.g., hovered). + virtual void SelectAutofillSuggestionAtIndex(int unique_id) = 0; + + // Inform the delegate that an Autofill suggestion has been chosen. Returns + // true if the suggestion was selected. + virtual bool DidAcceptAutofillSuggestion(const string16& value, + int unique_id, + unsigned index) = 0; + + // Remove the given Autocomplete entry from the DB. + virtual void RemoveAutocompleteEntry(const string16& value) = 0; + + // Remove the given Autofill profile or credit credit. + virtual void RemoveAutofillProfileOrCreditCard(int unique_id) = 0; + + // Informs the delegate that the Autofill previewed form should be cleared. + virtual void ClearPreviewedForm() = 0; + + // Called to inform the delegate the controller is experiencing destruction. + virtual void ControllerDestroyed() = 0; +}; + +#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_POPUP_DELEGATE_H_ diff --git a/chrome/browser/autofill/autofill_popup_unittest.cc b/chrome/browser/autofill/autofill_popup_unittest.cc deleted file mode 100644 index c4a99eb..0000000 --- a/chrome/browser/autofill/autofill_popup_unittest.cc +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) 2012 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 "base/memory/scoped_ptr.h" -#include "chrome/browser/autofill/autofill_popup_view.h" -#include "chrome/browser/autofill/test_autofill_external_delegate.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h" -#include "ui/gfx/rect.h" - -using ::testing::_; -using ::testing::AtLeast; -using WebKit::WebAutofillClient; - -namespace { - -class MockAutofillExternalDelegate : - public autofill::TestAutofillExternalDelegate { - public: - MockAutofillExternalDelegate() : TestAutofillExternalDelegate(NULL, NULL) {}; - virtual ~MockAutofillExternalDelegate() {}; - - virtual void SelectAutofillSuggestionAtIndex(int unique_id) - OVERRIDE {} - virtual void RemoveAutocompleteEntry(const string16& value) OVERRIDE {} - virtual void RemoveAutofillProfileOrCreditCard(int unique_id) OVERRIDE {} - virtual void ClearPreviewedForm() OVERRIDE {} - - MOCK_METHOD0(HideAutofillPopupInternal, void()); -}; - -class TestAutofillPopupView : public AutofillPopupView { - public: - explicit TestAutofillPopupView(AutofillExternalDelegate* external_delegate) : - AutofillPopupView(NULL, external_delegate, gfx::Rect()) {} - virtual ~TestAutofillPopupView() {} - - // Making protected functions public for testing - const std::vector<string16>& autofill_values() const { - return AutofillPopupView::autofill_values(); - } - int selected_line() const { - return AutofillPopupView::selected_line(); - } - void SetSelectedLine(size_t selected_line) { - AutofillPopupView::SetSelectedLine(selected_line); - } - void SelectNextLine() { - AutofillPopupView::SelectNextLine(); - } - void SelectPreviousLine() { - AutofillPopupView::SelectPreviousLine(); - } - bool RemoveSelectedLine() { - return AutofillPopupView::RemoveSelectedLine(); - } - - MOCK_METHOD1(InvalidateRow, void(size_t)); - MOCK_METHOD0(Hide, void()); - MOCK_METHOD0(UpdateBoundsAndRedrawPopupInternal, void()); - - private: - virtual void ShowInternal() OVERRIDE {} -}; - -} // namespace - -class AutofillPopupViewUnitTest : public ::testing::Test { - public: - AutofillPopupViewUnitTest() { - autofill_popup_view_.reset(new TestAutofillPopupView(&external_delegate_)); - } - virtual ~AutofillPopupViewUnitTest() {} - -protected: - scoped_ptr<TestAutofillPopupView> autofill_popup_view_; - MockAutofillExternalDelegate external_delegate_; -}; - -TEST_F(AutofillPopupViewUnitTest, SetBounds) { - // Ensure the popup size can be set and causes a redraw. - gfx::Rect popup_bounds(10, 10, 100, 100); - - EXPECT_CALL(*autofill_popup_view_, UpdateBoundsAndRedrawPopupInternal()); - - autofill_popup_view_->SetPopupBounds(popup_bounds); - - EXPECT_EQ(popup_bounds, autofill_popup_view_->popup_bounds()); -} - -TEST_F(AutofillPopupViewUnitTest, ChangeSelectedLine) { - // Set up the popup. - std::vector<string16> autofill_values(2, string16()); - std::vector<int> autofill_ids(2, 0); - autofill_popup_view_->Show(autofill_values, autofill_values, autofill_values, - autofill_ids); - - // To remove warnings. - EXPECT_CALL(*autofill_popup_view_, InvalidateRow(_)).Times(AtLeast(0)); - - EXPECT_LT(autofill_popup_view_->selected_line(), 0); - // Check that there are at least 2 values so that the first and last selection - // are different. - EXPECT_GE(2, - static_cast<int>(autofill_popup_view_->autofill_values().size())); - - // Test wrapping before the front. - autofill_popup_view_->SelectPreviousLine(); - EXPECT_EQ( - static_cast<int>(autofill_popup_view_->autofill_values().size() - 1), - autofill_popup_view_->selected_line()); - - // Test wrapping after the end. - autofill_popup_view_->SelectNextLine(); - EXPECT_EQ(0, autofill_popup_view_->selected_line()); -} - -TEST_F(AutofillPopupViewUnitTest, RedrawSelectedLine) { - // Set up the popup. - std::vector<string16> autofill_values(2, string16()); - std::vector<int> autofill_ids(2, 0); - autofill_popup_view_->Show(autofill_values, autofill_values, autofill_values, - autofill_ids); - - // Make sure that when a new line is selected, it is invalidated so it can - // be updated to show it is selected. - int selected_line = 0; - EXPECT_CALL(*autofill_popup_view_, InvalidateRow(selected_line)); - autofill_popup_view_->SetSelectedLine(selected_line); - - // Ensure that the row isn't invalidated if it didn't change. - EXPECT_CALL(*autofill_popup_view_, InvalidateRow(selected_line)).Times(0); - autofill_popup_view_->SetSelectedLine(selected_line); - - // Change back to no selection. - EXPECT_CALL(*autofill_popup_view_, InvalidateRow(selected_line)); - autofill_popup_view_->SetSelectedLine(-1); -} - -TEST_F(AutofillPopupViewUnitTest, RemoveLine) { - // Set up the popup. - std::vector<string16> autofill_values(3, string16()); - std::vector<int> autofill_ids; - autofill_ids.push_back(1); - autofill_ids.push_back(1); - autofill_ids.push_back(WebAutofillClient::MenuItemIDAutofillOptions); - autofill_popup_view_->Show(autofill_values, autofill_values, autofill_values, - autofill_ids); - - // Generate a popup, so it can be hidden later. It doesn't matter what the - // external_delegate thinks is being shown in the process, since we are just - // testing the popup here. - autofill::GenerateTestAutofillPopup(&external_delegate_); - - // To remove warnings. - EXPECT_CALL(*autofill_popup_view_, InvalidateRow(_)).Times(AtLeast(0)); - - // No line is selected so the removal should fail. - EXPECT_FALSE(autofill_popup_view_->RemoveSelectedLine()); - - // Try to remove the last entry and ensure it fails (it is an option). - autofill_popup_view_->SetSelectedLine( - autofill_popup_view_->autofill_values().size() - 1); - EXPECT_FALSE(autofill_popup_view_->RemoveSelectedLine()); - EXPECT_LE(0, autofill_popup_view_->selected_line()); - - // Remove the first entry. The popup should be redrawn since its size has - // changed. - EXPECT_CALL(*autofill_popup_view_, UpdateBoundsAndRedrawPopupInternal()); - autofill_popup_view_->SetSelectedLine(0); - EXPECT_TRUE(autofill_popup_view_->RemoveSelectedLine()); - - // Remove the last entry. The popup should then be hidden since there are - // no Autofill entries left. - EXPECT_CALL(external_delegate_, HideAutofillPopupInternal()); - - autofill_popup_view_->SetSelectedLine(0); - EXPECT_TRUE(autofill_popup_view_->RemoveSelectedLine()); -} - -TEST_F(AutofillPopupViewUnitTest, SkipSeparator) { - // Set up the popup. - std::vector<string16> autofill_values(3, string16()); - std::vector<int> autofill_ids; - autofill_ids.push_back(1); - autofill_ids.push_back(WebAutofillClient::MenuItemIDSeparator); - autofill_ids.push_back(WebAutofillClient::MenuItemIDAutofillOptions); - autofill_popup_view_->Show(autofill_values, autofill_values, autofill_values, - autofill_ids); - - // To remove warnings. - EXPECT_CALL(*autofill_popup_view_, InvalidateRow(_)).Times(AtLeast(0)); - - autofill_popup_view_->SetSelectedLine(0); - - // Make sure next skips the unselectable separator. - autofill_popup_view_->SelectNextLine(); - EXPECT_EQ(2, autofill_popup_view_->selected_line()); - - // Make sure previous skips the unselectable separator. - autofill_popup_view_->SelectPreviousLine(); - EXPECT_EQ(0, autofill_popup_view_->selected_line()); -} diff --git a/chrome/browser/autofill/autofill_popup_view.h b/chrome/browser/autofill/autofill_popup_view.h deleted file mode 100644 index aabbc2f..0000000 --- a/chrome/browser/autofill/autofill_popup_view.h +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2012 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_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ -#define CHROME_BROWSER_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ - -#include <vector> - -#include "base/compiler_specific.h" -#include "base/string16.h" -#include "ui/gfx/font.h" -#include "ui/gfx/rect.h" - -namespace content { -class WebContents; -} - -class AutofillExternalDelegate; - -class AutofillPopupView { - public: - explicit AutofillPopupView(content::WebContents* web_contents, - AutofillExternalDelegate* external_delegate_, - const gfx::Rect& element_bounds); - virtual ~AutofillPopupView(); - - // Hide the popup from view. Platform-indepent work. - virtual void Hide() = 0; - - // Display the autofill popup and fill it in with the values passed in. - // Platform-independent work. - void Show(const std::vector<string16>& autofill_values, - const std::vector<string16>& autofill_labels, - const std::vector<string16>& autofill_icons, - const std::vector<int>& autofill_unique_ids); - - // Update the bounds of the popup. - void SetPopupBounds(const gfx::Rect& bounds); - - // Sets the current Autofill pointer to NULL, used when the popup can outlive - // the delegate. - void ClearExternalDelegate(); - - const gfx::Rect& popup_bounds() { return popup_bounds_; } - - protected: - // Display the autofill popup and fill it in with the values passed in. - // Platform-dependent work. - virtual void ShowInternal() = 0; - - // Invalidate the given row and redraw it. - virtual void InvalidateRow(size_t row) = 0; - - // Ensure the popup is properly placed at |element_bounds_|. - virtual void UpdateBoundsAndRedrawPopupInternal() = 0; - - AutofillExternalDelegate* external_delegate() { return external_delegate_; } - - const gfx::Rect& element_bounds() const { return element_bounds_; } - - const std::vector<string16>& autofill_values() const { - return autofill_values_; - } - const std::vector<string16>& autofill_labels() const { - return autofill_labels_; - } - const std::vector<string16>& autofill_icons() const { - return autofill_icons_; - } - const std::vector<int>& autofill_unique_ids() const { - return autofill_unique_ids_; - } - -#if !defined(OS_ANDROID) - const gfx::Font& label_font() const { return label_font_; } - const gfx::Font& value_font() const { return value_font_; } -#endif - - int selected_line() const { return selected_line_; } - bool delete_icon_selected() const { return delete_icon_selected_; } - - // Recalculate the height and width of the popup and trigger a redraw. - void UpdateBoundsAndRedrawPopup(); - - // Change which line is selected by the user, based on coordinates. - void SetSelectedPosition(int x, int y); - - // Select the value at the given position. - void AcceptSelectedPosition(int x, int y); - - // Change which line is currently selected by the user. - void SetSelectedLine(int selected_line); - - // Clear the currently selected line so that nothing is selected. - void ClearSelectedLine(); - - // Increase the selected line by 1, properly handling wrapping. - void SelectNextLine(); - - // Decrease the selected line by 1, properly handling wrapping. - void SelectPreviousLine(); - - // The user has choosen the selected line. - bool AcceptSelectedLine(); - - // The user has removed a suggestion. - bool RemoveSelectedLine(); - - // Get the resource value for the given resource, returning -1 if the - // resource isn't recognized. - int GetIconResourceID(const string16& resource_name); - - // Returns true if the given id refers to an element that can be deleted. - bool CanDelete(int id); - -#if !defined(OS_ANDROID) - // Get width of popup needed by values. - int GetPopupRequiredWidth(); - - // Get height of popup needed by values. - int GetPopupRequiredHeight(); -#endif - - // Convert a y-coordinate to the closest line. - int LineFromY(int y); - - // Get the height of the given row. - int GetRowHeightFromId(int unique_id); - - // Returns the rectangle containing the item at position |index| in the popup. - gfx::Rect GetRectForRow(size_t row, int width); - - // Returns true if the given |x| and |y| coordinates refer to a point that - // hits the delete icon in the current selected line. - bool DeleteIconIsSelected(int x, int y); - - // Constants that are needed by the subclasses. - // The size of the boarder around the entire results popup, in pixels. - static const size_t kBorderThickness; - - // The amount of padding between icons in pixels. - static const size_t kIconPadding; - - // The amount of padding at the end of the popup in pixels. - static const size_t kEndPadding; - - // Height of the delete icon in pixels. - static const size_t kDeleteIconHeight; - - // Width of the delete icon in pixels. - static const size_t kDeleteIconWidth; - - // Height of the Autofill icons in pixels. - static const size_t kAutofillIconHeight; - - // Width of the Autofill icons in pixels. - static const size_t kAutofillIconWidth; - - private: - // Returns true if the given id refers to an element that can be accepted. - bool CanAccept(int id); - - // Returns true if the popup still has non-options entries to show the user. - bool HasAutofillEntries(); - - AutofillExternalDelegate* external_delegate_; - - // The bounds of the text element that is the focus of the Autofill. - const gfx::Rect element_bounds_; - - // The bounds of the Autofill popup. - gfx::Rect popup_bounds_; - - // The current Autofill query values. - std::vector<string16> autofill_values_; - std::vector<string16> autofill_labels_; - std::vector<string16> autofill_icons_; - std::vector<int> autofill_unique_ids_; - -#if !defined(OS_ANDROID) - // The fonts for the popup text. - gfx::Font value_font_; - gfx::Font label_font_; -#endif - - // The line that is currently selected by the user. - // |kNoSelection| indicates that no line is currently selected. - int selected_line_; - - // Used to indicate if the delete icon within a row is currently selected. - bool delete_icon_selected_; -}; - -#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ diff --git a/chrome/browser/autofill/test_autofill_external_delegate.cc b/chrome/browser/autofill/test_autofill_external_delegate.cc index 2610c58..90a03d5 100644 --- a/chrome/browser/autofill/test_autofill_external_delegate.cc +++ b/chrome/browser/autofill/test_autofill_external_delegate.cc @@ -40,9 +40,11 @@ void TestAutofillExternalDelegate::ApplyAutofillSuggestions( const std::vector<string16>& autofill_icons, const std::vector<int>& autofill_unique_ids) {} -void TestAutofillExternalDelegate::HideAutofillPopupInternal() {} +void TestAutofillExternalDelegate::HideAutofillPopup() {} void TestAutofillExternalDelegate::CreatePopupForElement( const gfx::Rect& element_bounds) {} +void TestAutofillExternalDelegate::ControllerDestroyed() {} + } // namespace autofill diff --git a/chrome/browser/autofill/test_autofill_external_delegate.h b/chrome/browser/autofill/test_autofill_external_delegate.h index 186a30a..3a6ff22 100644 --- a/chrome/browser/autofill/test_autofill_external_delegate.h +++ b/chrome/browser/autofill/test_autofill_external_delegate.h @@ -31,10 +31,12 @@ class TestAutofillExternalDelegate : public AutofillExternalDelegate { const std::vector<string16>& autofill_icons, const std::vector<int>& autofill_unique_ids) OVERRIDE; - virtual void HideAutofillPopupInternal() OVERRIDE; + virtual void HideAutofillPopup() OVERRIDE; virtual void CreatePopupForElement(const gfx::Rect& element_bounds) OVERRIDE; + virtual void ControllerDestroyed() OVERRIDE; + private: DISALLOW_COPY_AND_ASSIGN(TestAutofillExternalDelegate); }; diff --git a/chrome/browser/ui/android/autofill/autofill_external_delegate.cc b/chrome/browser/ui/android/autofill/autofill_external_delegate.cc deleted file mode 100644 index b4f7336..0000000 --- a/chrome/browser/ui/android/autofill/autofill_external_delegate.cc +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2012 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/ui/android/autofill/autofill_external_delegate.h" - -#include "base/string_util.h" -#include "chrome/browser/autofill/autofill_manager.h" -#include "chrome/browser/ui/android/autofill/autofill_popup_view_android.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" - -void AutofillExternalDelegate::CreateForWebContentsAndManager( - content::WebContents* web_contents, - AutofillManager* autofill_manager) { - if (FromWebContents(web_contents)) - return; - - web_contents->SetUserData( - UserDataKey(), - new AutofillExternalDelegateAndroid(web_contents, autofill_manager)); -} - -AutofillExternalDelegateAndroid::AutofillExternalDelegateAndroid( - content::WebContents* web_contents, AutofillManager* manager) - : AutofillExternalDelegate(web_contents, manager) { -} - -AutofillExternalDelegateAndroid::~AutofillExternalDelegateAndroid() { -} - -void AutofillExternalDelegateAndroid::ApplyAutofillSuggestions( - const std::vector<string16>& autofill_values, - const std::vector<string16>& autofill_labels, - const std::vector<string16>& autofill_icons, - const std::vector<int>& autofill_unique_ids) { - view_->Show(autofill_values, - autofill_labels, - autofill_icons, - autofill_unique_ids); -} - -void AutofillExternalDelegateAndroid::HideAutofillPopupInternal() { - if (!view_.get()) - return; - - view_->Hide(); - view_.reset(); -} - -void AutofillExternalDelegateAndroid::CreatePopupForElement( - const gfx::Rect& element_bounds) { - // TODO(aurimas): remove temporary fix for crbug.com/164900 - HideAutofillPopupInternal(); - - content::WebContents* contents = web_contents(); - view_.reset(new AutofillPopupViewAndroid(contents, this, element_bounds)); -} diff --git a/chrome/browser/ui/android/autofill/autofill_external_delegate.h b/chrome/browser/ui/android/autofill/autofill_external_delegate.h deleted file mode 100644 index e93b14b..0000000 --- a/chrome/browser/ui/android/autofill/autofill_external_delegate.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2012 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_UI_ANDROID_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_H_ -#define CHROME_BROWSER_UI_ANDROID_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_H_ - -#include "base/memory/scoped_ptr.h" -#include "chrome/browser/autofill/autofill_external_delegate.h" - -class AutofillPopupViewAndroid; - -// Android implementation of external delegate for display and selection of -// Autofill suggestions. -class AutofillExternalDelegateAndroid : public AutofillExternalDelegate { - public: - AutofillExternalDelegateAndroid(content::WebContents* web_contents, - AutofillManager* manager); - virtual ~AutofillExternalDelegateAndroid(); - - protected: - // AutofillExternalDelegate implementations. - virtual void ApplyAutofillSuggestions( - const std::vector<string16>& autofill_values, - const std::vector<string16>& autofill_labels, - const std::vector<string16>& autofill_icons, - const std::vector<int>& autofill_unique_ids) OVERRIDE; - virtual void CreatePopupForElement(const gfx::Rect& element_bounds) OVERRIDE; - virtual void HideAutofillPopupInternal() OVERRIDE; - - private: - scoped_ptr<AutofillPopupViewAndroid> view_; - - DISALLOW_COPY_AND_ASSIGN(AutofillExternalDelegateAndroid); -}; - -#endif // CHROME_BROWSER_UI_ANDROID_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_H_ diff --git a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc index fc0a28b..ef09d7d 100644 --- a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc +++ b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc @@ -2,44 +2,37 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "autofill_popup_view_android.h" +#include "chrome/browser/ui/android/autofill/autofill_popup_view_android.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h" -#include "base/android/scoped_java_ref.h" -#include "chrome/browser/ui/android/autofill/autofill_external_delegate.h" #include "chrome/browser/ui/android/window_android_helper.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller.h" #include "content/public/browser/android/content_view_core.h" -#include "content/public/browser/browser_thread.h" #include "jni/AutofillPopupGlue_jni.h" #include "ui/gfx/android/window_android.h" #include "ui/gfx/rect.h" using base::android::MethodID; -using content::BrowserThread; AutofillPopupViewAndroid::AutofillPopupViewAndroid( - content::WebContents* web_contents, - AutofillExternalDelegate* external_delegate, - const gfx::Rect& element_bounds) - : AutofillPopupView(web_contents, external_delegate, element_bounds), - web_contents_(web_contents) { + AutofillPopupController* controller) + : controller_(controller) { JNIEnv* env = base::android::AttachCurrentThread(); - content::ContentViewCore* content_view_core = - content::ContentViewCore::FromWebContents(web_contents); - ui::WindowAndroid* window_android = - WindowAndroidHelper::FromWebContents(web_contents_)->GetWindowAndroid(); + content::ContentViewCore* content_view_core = controller_->container_view(); - java_object_.Reset(Java_AutofillPopupGlue_create(env, - reinterpret_cast<jint>(this), window_android->GetJavaObject().obj(), + java_object_.Reset(Java_AutofillPopupGlue_create( + env, + reinterpret_cast<jint>(this), + content_view_core->GetWindowAndroid()->GetJavaObject().obj(), content_view_core->GetContainerViewDelegate().obj())); } AutofillPopupViewAndroid::~AutofillPopupViewAndroid() { + controller_->ViewDestroyed(); } -void AutofillPopupViewAndroid::ShowInternal() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +void AutofillPopupViewAndroid::Show() { UpdateBoundsAndRedrawPopup(); // We need an array of AutofillSuggestion. @@ -48,15 +41,17 @@ void AutofillPopupViewAndroid::ShowInternal() { base::android::GetClass(env, "org/chromium/chrome/browser/autofill/AutofillSuggestion"); ScopedJavaLocalRef<jobjectArray> data_array(env, - env->NewObjectArray(autofill_values().size(), + env->NewObjectArray(controller_->autofill_values().size(), autofill_suggestion_clazz.obj(), NULL)); base::android::CheckException(env); - for (size_t i = 0; i < autofill_values().size(); ++i) { + for (size_t i = 0; i < controller_->autofill_values().size(); ++i) { ScopedJavaLocalRef<jstring> value = - base::android::ConvertUTF16ToJavaString(env, autofill_values()[i]); + base::android::ConvertUTF16ToJavaString( + env, controller_->autofill_values()[i]); ScopedJavaLocalRef<jstring> label = - base::android::ConvertUTF16ToJavaString(env, autofill_labels()[i]); - int unique_id = autofill_unique_ids()[i]; + base::android::ConvertUTF16ToJavaString( + env, controller_->autofill_labels()[i]); + int unique_id = controller_->autofill_unique_ids()[i]; ScopedJavaLocalRef<jobject> data = Java_AutofillPopupGlue_createAutofillSuggestion(env, value.obj(), @@ -68,42 +63,46 @@ void AutofillPopupViewAndroid::ShowInternal() { Java_AutofillPopupGlue_show(env, java_object_.obj(), data_array.obj()); } + void AutofillPopupViewAndroid::Hide() { JNIEnv* env = base::android::AttachCurrentThread(); Java_AutofillPopupGlue_dismissFromNative(env, java_object_.obj()); } -void AutofillPopupViewAndroid::UpdateBoundsAndRedrawPopupInternal() { +void AutofillPopupViewAndroid::UpdateBoundsAndRedrawPopup() { JNIEnv* env = base::android::AttachCurrentThread(); Java_AutofillPopupGlue_setAnchorRect(env, java_object_.obj(), - element_bounds().x(), - element_bounds().y(), - element_bounds().width(), - element_bounds().height()); + controller_->element_bounds().x(), + controller_->element_bounds().y(), + controller_->element_bounds().width(), + controller_->element_bounds().height()); } -void AutofillPopupViewAndroid::SuggestionSelected(JNIEnv *env, +void AutofillPopupViewAndroid::SuggestionSelected(JNIEnv* env, jobject obj, jint list_index, jstring value, jint unique_id) { string16 value_utf16 = base::android::ConvertJavaStringToUTF16(env, value); - external_delegate()->DidAcceptAutofillSuggestions(value_utf16, - unique_id, - list_index); + controller_->AcceptAutofillSuggestion(value_utf16, + unique_id, + list_index); } -void AutofillPopupViewAndroid::Dismiss(JNIEnv *env, - jobject obj) { - external_delegate()->HideAutofillPopup(); +void AutofillPopupViewAndroid::Dismiss(JNIEnv* env, jobject obj) { + delete this; } -void AutofillPopupViewAndroid::InvalidateRow(size_t) { -} +void AutofillPopupViewAndroid::InvalidateRow(size_t) {} // static -bool AutofillPopupViewAndroid::RegisterAutofillPopupViewAndroid( - JNIEnv* env) { +bool AutofillPopupViewAndroid::RegisterAutofillPopupViewAndroid(JNIEnv* env) { return RegisterNativesImpl(env); } + +// static +AutofillPopupView* AutofillPopupView::Create( + AutofillPopupController* controller) { + return new AutofillPopupViewAndroid(controller); +} diff --git a/chrome/browser/ui/android/autofill/autofill_popup_view_android.h b/chrome/browser/ui/android/autofill/autofill_popup_view_android.h index b4f4d18..764abd6f 100644 --- a/chrome/browser/ui/android/autofill/autofill_popup_view_android.h +++ b/chrome/browser/ui/android/autofill/autofill_popup_view_android.h @@ -8,11 +8,10 @@ #include <jni.h> #include "base/android/scoped_java_ref.h" -#include "chrome/browser/autofill/autofill_popup_view.h" +#include "base/compiler_specific.h" +#include "chrome/browser/ui/autofill/autofill_popup_view.h" -namespace content { -class WebContents; -} +class AutofillPopupController; namespace gfx { class Rect; @@ -20,10 +19,7 @@ class Rect; class AutofillPopupViewAndroid : public AutofillPopupView { public: - AutofillPopupViewAndroid(content::WebContents* web_contents, - AutofillExternalDelegate* external_delegate, - const gfx::Rect& element_bounds); - virtual ~AutofillPopupViewAndroid(); + explicit AutofillPopupViewAndroid(AutofillPopupController* controller); // -------------------------------------------------------------------------- // Methods called from Java via JNI @@ -35,23 +31,23 @@ class AutofillPopupViewAndroid : public AutofillPopupView { jstring value, jint unique_id); - // AutofillPopupView implementation. - virtual void Hide() OVERRIDE; - void Dismiss(JNIEnv *env, jobject obj); static bool RegisterAutofillPopupViewAndroid(JNIEnv* env); protected: - // AutofillPopupView implementations. - virtual void ShowInternal() OVERRIDE; + // AutofillPopupView implementation. + virtual void Show() OVERRIDE; + virtual void Hide() OVERRIDE; virtual void InvalidateRow(size_t row) OVERRIDE; - virtual void UpdateBoundsAndRedrawPopupInternal() OVERRIDE; + virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; private: - content::WebContents* web_contents_; // weak; owns me. + virtual ~AutofillPopupViewAndroid(); + + AutofillPopupController* controller_; // weak. - // The corresponding AutofillExternalDelegate java object. + // The corresponding java object. base::android::ScopedJavaGlobalRef<jobject> java_object_; DISALLOW_COPY_AND_ASSIGN(AutofillPopupViewAndroid); diff --git a/chrome/browser/ui/autofill/autofill_popup_controller.h b/chrome/browser/ui/autofill/autofill_popup_controller.h new file mode 100644 index 0000000..67f2ca9 --- /dev/null +++ b/chrome/browser/ui/autofill/autofill_popup_controller.h @@ -0,0 +1,93 @@ +// Copyright (c) 2012 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_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_H_ +#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_H_ + +#include <vector> + +#include "base/compiler_specific.h" +#include "ui/gfx/native_widget_types.h" + +namespace gfx { +class Font; +class Point; +class Rect; +} + +// This interface provides data to an AutofillPopupView. +class AutofillPopupController { + public: + // Called when the view is going down. + virtual void ViewDestroyed() = 0; + + // Recalculate the height and width of the popup and trigger a redraw. + virtual void UpdateBoundsAndRedrawPopup() = 0; + + // Change which line is selected by the user, based on coordinates. + virtual void SetSelectedPosition(int x, int y) = 0; + + // Accepts the described Autofill suggestion. + virtual bool AcceptAutofillSuggestion(const string16& value, + int unique_id, + unsigned index) = 0; + + // Select the value at the given position. + virtual void AcceptSelectedPosition(int x, int y) = 0; + + // Clear the currently selected line so that nothing is selected. + virtual void ClearSelectedLine() = 0; + + // Get the resource value for the given resource, returning -1 if the + // resource isn't recognized. + virtual int GetIconResourceID(const string16& resource_name) = 0; + + // Returns true if the given id refers to an element that can be deleted. + virtual bool CanDelete(int id) = 0; + +#if !defined(OS_ANDROID) + // Get width of popup needed by values. + virtual int GetPopupRequiredWidth() = 0; + + // Get height of popup needed by values. + virtual int GetPopupRequiredHeight() = 0; +#endif + + // Updates the bounds of the popup and initiates a redraw. + virtual void SetPopupBounds(const gfx::Rect& bounds) = 0; + + // Get the height of the given row. + virtual int GetRowHeightFromId(int unique_id) = 0; + + // Returns the rectangle containing the item at position |row| in the popup. + // |row| is the index of the row, and |width| is its width. + virtual gfx::Rect GetRectForRow(size_t row, int width) = 0; + + // The actual bounds of the popup. + virtual const gfx::Rect& popup_bounds() const = 0; + + // The view that the form field element sits in. + virtual gfx::NativeView container_view() const = 0; + + // The bounds of the form field element (relative to |container_origin|). + virtual const gfx::Rect& element_bounds() const = 0; + + virtual const std::vector<string16>& autofill_values() const = 0; + virtual const std::vector<string16>& autofill_labels() const = 0; + virtual const std::vector<string16>& autofill_icons() const = 0; + virtual const std::vector<int>& autofill_unique_ids() const = 0; + +#if !defined(OS_ANDROID) + virtual const gfx::Font& label_font() const = 0; + virtual const gfx::Font& value_font() const = 0; +#endif + + virtual int selected_line() const = 0; + virtual bool delete_icon_hovered() const = 0; + + protected: + virtual ~AutofillPopupController() {} +}; + +#endif // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_H_ diff --git a/chrome/browser/autofill/autofill_popup_view.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index 9713d3e..ae01eb0 100644 --- a/chrome/browser/autofill/autofill_popup_view.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc @@ -2,14 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/autofill/autofill_popup_view.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" #include "base/logging.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/autofill/autofill_external_delegate.h" -#include "content/public/browser/web_contents.h" +#include "chrome/browser/ui/autofill/autofill_popup_view.h" +#include "content/public/browser/native_web_keyboard_event.h" #include "grit/webkit_resources.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h" +#include "ui/base/events/event.h" using WebKit::WebAutofillClient; @@ -33,6 +34,14 @@ const size_t kLabelPadding = 15; // The maximum amount of characters to display from either the label or value. const size_t kMaxTextLength = 15; +#if !defined(OS_ANDROID) +const size_t kIconPadding = AutofillPopupView::kIconPadding; +const size_t kEndPadding = AutofillPopupView::kEndPadding; +const size_t kDeleteIconHeight = AutofillPopupView::kDeleteIconHeight; +const size_t kDeleteIconWidth = AutofillPopupView::kDeleteIconWidth; +const size_t kAutofillIconWidth = AutofillPopupView::kAutofillIconWidth; +#endif + struct DataResource { const char* name; int id; @@ -51,36 +60,31 @@ const DataResource kDataResources[] = { } // end namespace -const size_t AutofillPopupView::kBorderThickness = 1; -const size_t AutofillPopupView::kIconPadding = 5; -const size_t AutofillPopupView::kEndPadding = 3; -const size_t AutofillPopupView::kDeleteIconHeight = 16; -const size_t AutofillPopupView::kDeleteIconWidth = 16; -const size_t AutofillPopupView::kAutofillIconHeight = 16; -const size_t AutofillPopupView::kAutofillIconWidth = 25; - -AutofillPopupView::AutofillPopupView( - content::WebContents* web_contents, - AutofillExternalDelegate* external_delegate, +AutofillPopupControllerImpl::AutofillPopupControllerImpl( + AutofillPopupDelegate* delegate, + gfx::NativeView container_view, const gfx::Rect& element_bounds) - : external_delegate_(external_delegate), + : view_(NULL), + delegate_(delegate), + container_view_(container_view), element_bounds_(element_bounds), selected_line_(kNoSelection), - delete_icon_selected_(false) { - if (!web_contents) - return; - + delete_icon_hovered_(false) { #if !defined(OS_ANDROID) label_font_ = value_font_.DeriveFont(kLabelFontSizeDelta); #endif } -AutofillPopupView::~AutofillPopupView() {} +AutofillPopupControllerImpl::~AutofillPopupControllerImpl() { + if (delegate_) + delegate_->ControllerDestroyed(); +} -void AutofillPopupView::Show(const std::vector<string16>& autofill_values, - const std::vector<string16>& autofill_labels, - const std::vector<string16>& autofill_icons, - const std::vector<int>& autofill_unique_ids) { +void AutofillPopupControllerImpl::Show( + const std::vector<string16>& autofill_values, + const std::vector<string16>& autofill_labels, + const std::vector<string16>& autofill_icons, + const std::vector<int>& autofill_unique_ids) { autofill_values_ = autofill_values; autofill_labels_ = autofill_labels; autofill_icons_ = autofill_icons; @@ -98,49 +102,233 @@ void AutofillPopupView::Show(const std::vector<string16>& autofill_values, } #endif - ShowInternal(); + if (!view_) { + view_ = AutofillPopupView::Create(this); + ShowView(); + } else { + UpdateBoundsAndRedrawPopup(); + } } -void AutofillPopupView::SetPopupBounds(const gfx::Rect& bounds) { - popup_bounds_ = bounds; - UpdateBoundsAndRedrawPopupInternal(); +void AutofillPopupControllerImpl::Hide() { + if (view_) + view_->Hide(); + else + delete this; +} + +void AutofillPopupControllerImpl::DelegateDestroyed() { + delegate_ = NULL; + Hide(); } -void AutofillPopupView::ClearExternalDelegate() { - external_delegate_ = NULL; +void AutofillPopupControllerImpl::ViewDestroyed() { + delete this; } -void AutofillPopupView::UpdateBoundsAndRedrawPopup() { +void AutofillPopupControllerImpl::UpdateBoundsAndRedrawPopup() { #if !defined(OS_ANDROID) popup_bounds_.set_width(GetPopupRequiredWidth()); popup_bounds_.set_height(GetPopupRequiredHeight()); #endif - UpdateBoundsAndRedrawPopupInternal(); + view_->UpdateBoundsAndRedrawPopup(); } -void AutofillPopupView::SetSelectedPosition(int x, int y) { +void AutofillPopupControllerImpl::SetSelectedPosition(int x, int y) { int line = LineFromY(y); SetSelectedLine(line); - bool delete_icon_selected = DeleteIconIsSelected(x, y); - if (delete_icon_selected != delete_icon_selected_) { - delete_icon_selected_ = delete_icon_selected; + bool delete_icon_hovered = DeleteIconIsUnder(x, y); + if (delete_icon_hovered != delete_icon_hovered_) { + delete_icon_hovered_ = delete_icon_hovered; InvalidateRow(selected_line()); } } -void AutofillPopupView::AcceptSelectedPosition(int x, int y) { +bool AutofillPopupControllerImpl::AcceptAutofillSuggestion( + const string16& value, + int unique_id, + unsigned index) { + return delegate_->DidAcceptAutofillSuggestion(value, unique_id, index); +} + +void AutofillPopupControllerImpl::AcceptSelectedPosition(int x, int y) { DCHECK_EQ(selected_line(), LineFromY(y)); - if (DeleteIconIsSelected(x, y)) + if (DeleteIconIsUnder(x, y)) RemoveSelectedLine(); else AcceptSelectedLine(); } -void AutofillPopupView::SetSelectedLine(int selected_line) { +void AutofillPopupControllerImpl::ClearSelectedLine() { + SetSelectedLine(kNoSelection); +} + +int AutofillPopupControllerImpl::GetIconResourceID( + const string16& resource_name) { + for (size_t i = 0; i < arraysize(kDataResources); ++i) { + if (resource_name == ASCIIToUTF16(kDataResources[i].name)) + return kDataResources[i].id; + } + + return -1; +} + +bool AutofillPopupControllerImpl::CanDelete(int id) { + return id > 0 || + id == WebAutofillClient::MenuItemIDAutocompleteEntry || + id == WebAutofillClient::MenuItemIDPasswordEntry; +} + +#if !defined(OS_ANDROID) +int AutofillPopupControllerImpl::GetPopupRequiredWidth() { + if (value_font_.platform_font() == NULL || + label_font_.platform_font() == NULL) { + // We can't calculate the size of the popup if the fonts + // aren't present. + return 0; + } + + int popup_width = element_bounds().width(); + DCHECK_EQ(autofill_values().size(), autofill_labels().size()); + for (size_t i = 0; i < autofill_values().size(); ++i) { + int row_size = kEndPadding + + value_font_.GetStringWidth(autofill_values()[i]) + + kLabelPadding + + label_font_.GetStringWidth(autofill_labels()[i]); + + // Add the Autofill icon size, if required. + if (!autofill_icons()[i].empty()) + row_size += kAutofillIconWidth + kIconPadding; + + // Add delete icon, if required. + if (CanDelete(autofill_unique_ids()[i])) + row_size += kDeleteIconWidth + kIconPadding; + + // Add the padding at the end + row_size += kEndPadding; + + popup_width = std::max(popup_width, row_size); + } + + return popup_width; +} + +int AutofillPopupControllerImpl::GetPopupRequiredHeight() { + int popup_height = 0; + + for (size_t i = 0; i < autofill_unique_ids().size(); ++i) { + popup_height += GetRowHeightFromId(autofill_unique_ids()[i]); + } + + return popup_height; +} +#endif // !defined(OS_ANDROID) + +int AutofillPopupControllerImpl::GetRowHeightFromId(int unique_id) { + if (unique_id == WebAutofillClient::MenuItemIDSeparator) + return kSeparatorHeight; + + return kRowHeight; +} + +gfx::Rect AutofillPopupControllerImpl::GetRectForRow(size_t row, int width) { + int top = 0; + for (size_t i = 0; i < row; ++i) { + top += GetRowHeightFromId(autofill_unique_ids()[i]); + } + + return gfx::Rect( + 0, top, width, GetRowHeightFromId(autofill_unique_ids()[row])); +} + +void AutofillPopupControllerImpl::SetPopupBounds(const gfx::Rect& bounds) { + popup_bounds_ = bounds; + UpdateBoundsAndRedrawPopup(); +} + +const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const { + return popup_bounds_; +} + +gfx::NativeView AutofillPopupControllerImpl::container_view() const { + return container_view_; +} + +const gfx::Rect& AutofillPopupControllerImpl::element_bounds() const { + return element_bounds_; +} + +const std::vector<string16>& AutofillPopupControllerImpl:: + autofill_values() const { + return autofill_values_; +} + +const std::vector<string16>& AutofillPopupControllerImpl:: + autofill_labels() const { + return autofill_labels_; +} + +const std::vector<string16>& AutofillPopupControllerImpl:: + autofill_icons() const { + return autofill_icons_; +} + +const std::vector<int>& AutofillPopupControllerImpl:: + autofill_unique_ids() const { + return autofill_unique_ids_; +} + +#if !defined(OS_ANDROID) +const gfx::Font& AutofillPopupControllerImpl::label_font() const { + return label_font_; +} + +const gfx::Font& AutofillPopupControllerImpl::value_font() const { + return value_font_; +} +#endif + +int AutofillPopupControllerImpl::selected_line() const { + return selected_line_; +} + +bool AutofillPopupControllerImpl::delete_icon_hovered() const { + return delete_icon_hovered_; +} + +bool AutofillPopupControllerImpl::HandleKeyPressEvent( + const content::NativeWebKeyboardEvent& event) { + switch (event.windowsKeyCode) { + case ui::VKEY_UP: + SelectPreviousLine(); + return true; + case ui::VKEY_DOWN: + SelectNextLine(); + return true; + case ui::VKEY_PRIOR: // Page up. + SetSelectedLine(0); + return true; + case ui::VKEY_NEXT: // Page down. + SetSelectedLine(autofill_values().size() - 1); + return true; + case ui::VKEY_ESCAPE: + Hide(); + return true; + case ui::VKEY_DELETE: + return (event.modifiers & content::NativeWebKeyboardEvent::ShiftKey) && + RemoveSelectedLine(); + case ui::VKEY_RETURN: + return AcceptSelectedLine(); + default: + return false; + } +} + +void AutofillPopupControllerImpl::SetSelectedLine(int selected_line) { if (selected_line_ == selected_line) return; @@ -153,16 +341,12 @@ void AutofillPopupView::SetSelectedLine(int selected_line) { selected_line_ = selected_line; if (selected_line_ != kNoSelection) { - external_delegate_->SelectAutofillSuggestionAtIndex( + delegate_->SelectAutofillSuggestionAtIndex( autofill_unique_ids_[selected_line_]); } } -void AutofillPopupView::ClearSelectedLine() { - SetSelectedLine(kNoSelection); -} - -void AutofillPopupView::SelectNextLine() { +void AutofillPopupControllerImpl::SelectNextLine() { int new_selected_line = selected_line_ + 1; // Skip over any lines that can't be selected. @@ -177,7 +361,7 @@ void AutofillPopupView::SelectNextLine() { SetSelectedLine(new_selected_line); } -void AutofillPopupView::SelectPreviousLine() { +void AutofillPopupControllerImpl::SelectPreviousLine() { int new_selected_line = selected_line_ - 1; // Skip over any lines that can't be selected. @@ -192,7 +376,7 @@ void AutofillPopupView::SelectPreviousLine() { SetSelectedLine(new_selected_line); } -bool AutofillPopupView::AcceptSelectedLine() { +bool AutofillPopupControllerImpl::AcceptSelectedLine() { if (selected_line_ == kNoSelection) return false; @@ -202,13 +386,13 @@ bool AutofillPopupView::AcceptSelectedLine() { if (!CanAccept(autofill_unique_ids_[selected_line_])) return false; - return external_delegate()->DidAcceptAutofillSuggestions( + return AcceptAutofillSuggestion( autofill_values_[selected_line_], autofill_unique_ids_[selected_line_], selected_line_); } -bool AutofillPopupView::RemoveSelectedLine() { +bool AutofillPopupControllerImpl::RemoveSelectedLine() { if (selected_line_ == kNoSelection) return false; @@ -219,10 +403,10 @@ bool AutofillPopupView::RemoveSelectedLine() { return false; if (autofill_unique_ids_[selected_line_] > 0) { - external_delegate()->RemoveAutofillProfileOrCreditCard( + delegate_->RemoveAutofillProfileOrCreditCard( autofill_unique_ids_[selected_line_]); } else { - external_delegate()->RemoveAutocompleteEntry( + delegate_->RemoveAutocompleteEntry( autofill_values_[selected_line_]); } @@ -235,76 +419,16 @@ bool AutofillPopupView::RemoveSelectedLine() { SetSelectedLine(kNoSelection); if (HasAutofillEntries()) { - external_delegate_->ClearPreviewedForm(); + delegate_->ClearPreviewedForm(); UpdateBoundsAndRedrawPopup(); } else { - external_delegate_->HideAutofillPopup(); + Hide(); } return true; } -int AutofillPopupView::GetIconResourceID(const string16& resource_name) { - for (size_t i = 0; i < arraysize(kDataResources); ++i) { - if (resource_name == ASCIIToUTF16(kDataResources[i].name)) - return kDataResources[i].id; - } - - return -1; -} - -bool AutofillPopupView::CanDelete(int id) { - return id > 0 || - id == WebAutofillClient::MenuItemIDAutocompleteEntry || - id == WebAutofillClient::MenuItemIDPasswordEntry; -} - -#if !defined(OS_ANDROID) -int AutofillPopupView::GetPopupRequiredWidth() { - if (value_font_.platform_font() == NULL || - label_font_.platform_font() == NULL) { - // We can't calculate the size of the popup if the fonts - // aren't present. - return 0; - } - - int popup_width = element_bounds().width(); - DCHECK_EQ(autofill_values().size(), autofill_labels().size()); - for (size_t i = 0; i < autofill_values().size(); ++i) { - int row_size = kEndPadding + - value_font_.GetStringWidth(autofill_values()[i]) + - kLabelPadding + - label_font_.GetStringWidth(autofill_labels()[i]); - - // Add the Autofill icon size, if required. - if (!autofill_icons()[i].empty()) - row_size += kAutofillIconWidth + kIconPadding; - - // Add delete icon, if required. - if (CanDelete(autofill_unique_ids()[i])) - row_size += kDeleteIconWidth + kIconPadding; - - // Add the padding at the end - row_size += kEndPadding; - - popup_width = std::max(popup_width, row_size); - } - - return popup_width; -} - -int AutofillPopupView::GetPopupRequiredHeight() { - int popup_height = 0; - - for (size_t i = 0; i < autofill_unique_ids().size(); ++i) { - popup_height += GetRowHeightFromId(autofill_unique_ids()[i]); - } - - return popup_height; -} -#endif // !defined(OS_ANDROID) - -int AutofillPopupView::LineFromY(int y) { +int AutofillPopupControllerImpl::LineFromY(int y) { int current_height = 0; for (size_t i = 0; i < autofill_unique_ids().size(); ++i) { @@ -318,24 +442,7 @@ int AutofillPopupView::LineFromY(int y) { return autofill_unique_ids().size() - 1; } -int AutofillPopupView::GetRowHeightFromId(int unique_id) { - if (unique_id == WebAutofillClient::MenuItemIDSeparator) - return kSeparatorHeight; - - return kRowHeight; -} - -gfx::Rect AutofillPopupView::GetRectForRow(size_t row, int width) { - int top = 0; - for (size_t i = 0; i < row; ++i) { - top += GetRowHeightFromId(autofill_unique_ids()[i]); - } - - return gfx::Rect( - 0, top, width, GetRowHeightFromId(autofill_unique_ids()[row])); -} - -bool AutofillPopupView::DeleteIconIsSelected(int x, int y) { +bool AutofillPopupControllerImpl::DeleteIconIsUnder(int x, int y) { #if defined(OS_ANDROID) return false; #else @@ -357,15 +464,23 @@ bool AutofillPopupView::DeleteIconIsSelected(int x, int y) { #endif } -bool AutofillPopupView::CanAccept(int id) { +bool AutofillPopupControllerImpl::CanAccept(int id) { return id != WebAutofillClient::MenuItemIDSeparator; } -bool AutofillPopupView::HasAutofillEntries() { +bool AutofillPopupControllerImpl::HasAutofillEntries() { return autofill_values_.size() != 0 && (autofill_unique_ids_[0] > 0 || autofill_unique_ids_[0] == - WebAutofillClient::MenuItemIDAutocompleteEntry || + WebAutofillClient::MenuItemIDAutocompleteEntry || autofill_unique_ids_[0] == WebAutofillClient::MenuItemIDPasswordEntry || autofill_unique_ids_[0] == WebAutofillClient::MenuItemIDDataListEntry); } + +void AutofillPopupControllerImpl::ShowView() { + view_->Show(); +} + +void AutofillPopupControllerImpl::InvalidateRow(size_t row) { + view_->InvalidateRow(row); +} diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h new file mode 100644 index 0000000..54cda77 --- /dev/null +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h @@ -0,0 +1,150 @@ +// Copyright (c) 2012 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_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_IMPL_H_ +#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_IMPL_H_ + +#include "base/gtest_prod_util.h" +#include "base/string16.h" +#include "chrome/browser/autofill/autofill_popup_delegate.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller.h" +#include "content/public/browser/keyboard_listener.h" +#include "ui/gfx/font.h" +#include "ui/gfx/rect.h" + +class AutofillPopupView; + +namespace ui { +class KeyEvent; +} + +// This class is a controller for an AutofillPopupView. It implements +// AutofillPopupController to allow calls from AutofillPopupView. The +// other, public functions are available to its instantiator. +class AutofillPopupControllerImpl : public AutofillPopupController, + public content::KeyboardListener { + public: + AutofillPopupControllerImpl(AutofillPopupDelegate* delegate, + gfx::NativeView container_view, + const gfx::Rect& element_bounds); + + // Shows the popup, or updates the existing popup with the given values. + void Show(const std::vector<string16>& autofill_values, + const std::vector<string16>& autofill_labels, + const std::vector<string16>& autofill_icons, + const std::vector<int>& autofill_unique_ids); + + // Hides the popup and destroys the controller. + void Hide(); + + // Called when |delegate_| is no longer valid. + void DelegateDestroyed(); + + protected: + FRIEND_TEST_ALL_PREFIXES(AutofillExternalDelegateBrowserTest, + CloseWidgetAndNoLeaking); + virtual ~AutofillPopupControllerImpl(); + + // AutofillPopupController implementation. + virtual void ViewDestroyed() OVERRIDE; + virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; + virtual void SetSelectedPosition(int x, int y) OVERRIDE; + virtual bool AcceptAutofillSuggestion(const string16& value, + int unique_id, + unsigned index) OVERRIDE; + virtual void AcceptSelectedPosition(int x, int y) OVERRIDE; + virtual void ClearSelectedLine() OVERRIDE; + virtual int GetIconResourceID(const string16& resource_name) OVERRIDE; + virtual bool CanDelete(int id) OVERRIDE; +#if !defined(OS_ANDROID) + virtual int GetPopupRequiredWidth() OVERRIDE; + virtual int GetPopupRequiredHeight() OVERRIDE; +#endif + virtual int GetRowHeightFromId(int unique_id) OVERRIDE; + virtual gfx::Rect GetRectForRow(size_t row, int width) OVERRIDE; + virtual void SetPopupBounds(const gfx::Rect& bounds) OVERRIDE; + virtual const gfx::Rect& popup_bounds() const OVERRIDE; + virtual gfx::NativeView container_view() const OVERRIDE; + virtual const gfx::Rect& element_bounds() const OVERRIDE; + virtual const std::vector<string16>& autofill_values() const OVERRIDE; + virtual const std::vector<string16>& autofill_labels() const OVERRIDE; + virtual const std::vector<string16>& autofill_icons() const OVERRIDE; + virtual const std::vector<int>& autofill_unique_ids() const OVERRIDE; +#if !defined(OS_ANDROID) + virtual const gfx::Font& label_font() const OVERRIDE; + virtual const gfx::Font& value_font() const OVERRIDE; +#endif + virtual int selected_line() const OVERRIDE; + virtual bool delete_icon_hovered() const OVERRIDE; + + // KeyboardListener implementation. + virtual bool HandleKeyPressEvent( + const content::NativeWebKeyboardEvent& event) OVERRIDE; + + // Change which line is currently selected by the user. + void SetSelectedLine(int selected_line); + + // Increase the selected line by 1, properly handling wrapping. + void SelectNextLine(); + + // Decrease the selected line by 1, properly handling wrapping. + void SelectPreviousLine(); + + // The user has choosen the selected line. + bool AcceptSelectedLine(); + + // The user has removed a suggestion. + bool RemoveSelectedLine(); + + // Convert a y-coordinate to the closest line. + int LineFromY(int y); + + // Returns true if the given |x| and |y| coordinates refer to a point that + // hits the delete icon in the current selected line. + bool DeleteIconIsUnder(int x, int y); + + // Returns true if the given id refers to an element that can be accepted. + bool CanAccept(int id); + + // Returns true if the popup still has non-options entries to show the user. + bool HasAutofillEntries(); + + AutofillPopupView* view() { return view_; } + + // |view_| pass throughs (virtual for testing). + virtual void ShowView(); + virtual void InvalidateRow(size_t row); + + private: + AutofillPopupView* view_; // Weak reference. + AutofillPopupDelegate* delegate_; // Weak reference. + gfx::NativeView container_view_; // Weak reference. + + // The bounds of the text element that is the focus of the Autofill. + const gfx::Rect element_bounds_; + + // The bounds of the Autofill popup. + gfx::Rect popup_bounds_; + + // The current Autofill query values. + std::vector<string16> autofill_values_; + std::vector<string16> autofill_labels_; + std::vector<string16> autofill_icons_; + std::vector<int> autofill_unique_ids_; + +#if !defined(OS_ANDROID) + // The fonts for the popup text. + gfx::Font value_font_; + gfx::Font label_font_; +#endif + + // The line that is currently selected by the user. + // |kNoSelection| indicates that no line is currently selected. + int selected_line_; + + // Used to indicate if the delete icon within a row is currently selected. + bool delete_icon_hovered_; +}; + +#endif // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_IMPL_H_ diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc new file mode 100644 index 0000000..ad13318 --- /dev/null +++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc @@ -0,0 +1,208 @@ +// Copyright (c) 2012 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 "base/memory/scoped_ptr.h" +#include "chrome/browser/autofill/test_autofill_external_delegate.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h" +#include "ui/gfx/rect.h" + +using ::testing::_; +using ::testing::AtLeast; +using WebKit::WebAutofillClient; + +namespace { + +class MockAutofillExternalDelegate : + public autofill::TestAutofillExternalDelegate { + public: + MockAutofillExternalDelegate() : TestAutofillExternalDelegate(NULL, NULL) {}; + virtual ~MockAutofillExternalDelegate() {}; + + virtual void SelectAutofillSuggestionAtIndex(int unique_id) + OVERRIDE {} + virtual void RemoveAutocompleteEntry(const string16& value) OVERRIDE {} + virtual void RemoveAutofillProfileOrCreditCard(int unique_id) OVERRIDE {} + virtual void ClearPreviewedForm() OVERRIDE {} + + MOCK_METHOD0(ControllerDestroyed, void()); +}; + +class TestAutofillPopupController : public AutofillPopupControllerImpl { + public: + explicit TestAutofillPopupController( + AutofillExternalDelegate* external_delegate) + : AutofillPopupControllerImpl(external_delegate, NULL, gfx::Rect()) {} + virtual ~TestAutofillPopupController() {} + + // Making protected functions public for testing + const std::vector<string16>& autofill_values() const { + return AutofillPopupControllerImpl::autofill_values(); + } + int selected_line() const { + return AutofillPopupControllerImpl::selected_line(); + } + void SetSelectedLine(size_t selected_line) { + AutofillPopupControllerImpl::SetSelectedLine(selected_line); + } + void SelectNextLine() { + AutofillPopupControllerImpl::SelectNextLine(); + } + void SelectPreviousLine() { + AutofillPopupControllerImpl::SelectPreviousLine(); + } + bool RemoveSelectedLine() { + return AutofillPopupControllerImpl::RemoveSelectedLine(); + } + + MOCK_METHOD1(InvalidateRow, void(size_t)); + MOCK_METHOD0(Hide, void()); + MOCK_METHOD0(UpdateBoundsAndRedrawPopup, void()); + + private: + virtual void ShowView() OVERRIDE {} +}; + +} // namespace + +class AutofillPopupControllerUnitTest : public ::testing::Test { + public: + AutofillPopupControllerUnitTest() { + autofill_popup_controller_.reset( + new testing::NiceMock<TestAutofillPopupController>( + &external_delegate_)); + } + virtual ~AutofillPopupControllerUnitTest() {} + + AutofillPopupController* popup_controller() { + return autofill_popup_controller_.get(); + } + +protected: + testing::NiceMock<MockAutofillExternalDelegate> external_delegate_; + scoped_ptr<testing::NiceMock<TestAutofillPopupController> > + autofill_popup_controller_; +}; + +TEST_F(AutofillPopupControllerUnitTest, SetBounds) { + // Ensure the popup size can be set and causes a redraw. + gfx::Rect popup_bounds(10, 10, 100, 100); + + EXPECT_CALL(*autofill_popup_controller_, + UpdateBoundsAndRedrawPopup()); + + popup_controller()->SetPopupBounds(popup_bounds); + + EXPECT_EQ(popup_bounds, popup_controller()->popup_bounds()); +} + +TEST_F(AutofillPopupControllerUnitTest, ChangeSelectedLine) { + // Set up the popup. + std::vector<string16> autofill_values(2, string16()); + std::vector<int> autofill_ids(2, 0); + autofill_popup_controller_->Show( + autofill_values, autofill_values, autofill_values, autofill_ids); + + EXPECT_LT(autofill_popup_controller_->selected_line(), 0); + // Check that there are at least 2 values so that the first and last selection + // are different. + EXPECT_GE(2, + static_cast<int>(autofill_popup_controller_->autofill_values().size())); + + // Test wrapping before the front. + autofill_popup_controller_->SelectPreviousLine(); + EXPECT_EQ(static_cast<int>( + autofill_popup_controller_->autofill_values().size() - 1), + autofill_popup_controller_->selected_line()); + + // Test wrapping after the end. + autofill_popup_controller_->SelectNextLine(); + EXPECT_EQ(0, autofill_popup_controller_->selected_line()); +} + +TEST_F(AutofillPopupControllerUnitTest, RedrawSelectedLine) { + // Set up the popup. + std::vector<string16> autofill_values(2, string16()); + std::vector<int> autofill_ids(2, 0); + autofill_popup_controller_->Show( + autofill_values, autofill_values, autofill_values, + autofill_ids); + + // Make sure that when a new line is selected, it is invalidated so it can + // be updated to show it is selected. + int selected_line = 0; + EXPECT_CALL(*autofill_popup_controller_, InvalidateRow(selected_line)); + autofill_popup_controller_->SetSelectedLine(selected_line); + + // Ensure that the row isn't invalidated if it didn't change. + EXPECT_CALL(*autofill_popup_controller_, + InvalidateRow(selected_line)).Times(0); + autofill_popup_controller_->SetSelectedLine(selected_line); + + // Change back to no selection. + EXPECT_CALL(*autofill_popup_controller_, InvalidateRow(selected_line)); + autofill_popup_controller_->SetSelectedLine(-1); +} + +TEST_F(AutofillPopupControllerUnitTest, RemoveLine) { + // Set up the popup. + std::vector<string16> autofill_values(3, string16()); + std::vector<int> autofill_ids; + autofill_ids.push_back(1); + autofill_ids.push_back(1); + autofill_ids.push_back(WebAutofillClient::MenuItemIDAutofillOptions); + autofill_popup_controller_->Show( + autofill_values, autofill_values, autofill_values, autofill_ids); + + // Generate a popup, so it can be hidden later. It doesn't matter what the + // external_delegate thinks is being shown in the process, since we are just + // testing the popup here. + autofill::GenerateTestAutofillPopup(&external_delegate_); + + // No line is selected so the removal should fail. + EXPECT_FALSE(autofill_popup_controller_->RemoveSelectedLine()); + + // Try to remove the last entry and ensure it fails (it is an option). + autofill_popup_controller_->SetSelectedLine( + autofill_popup_controller_->autofill_values().size() - 1); + EXPECT_FALSE(autofill_popup_controller_->RemoveSelectedLine()); + EXPECT_LE(0, autofill_popup_controller_->selected_line()); + + // Remove the first entry. The popup should be redrawn since its size has + // changed. + EXPECT_CALL(*autofill_popup_controller_, UpdateBoundsAndRedrawPopup()); + autofill_popup_controller_->SetSelectedLine(0); + EXPECT_TRUE(autofill_popup_controller_->RemoveSelectedLine()); + + // Remove the last entry. The popup should then be hidden since there are + // no Autofill entries left. + EXPECT_CALL(external_delegate_, ControllerDestroyed()); + + autofill_popup_controller_->SetSelectedLine(0); + // The controller self-deletes here, don't double delete. + EXPECT_TRUE(autofill_popup_controller_.release()->RemoveSelectedLine()); +} + +TEST_F(AutofillPopupControllerUnitTest, SkipSeparator) { + // Set up the popup. + std::vector<string16> autofill_values(3, string16()); + std::vector<int> autofill_ids; + autofill_ids.push_back(1); + autofill_ids.push_back(WebAutofillClient::MenuItemIDSeparator); + autofill_ids.push_back(WebAutofillClient::MenuItemIDAutofillOptions); + autofill_popup_controller_->Show( + autofill_values, autofill_values, autofill_values, autofill_ids); + + autofill_popup_controller_->SetSelectedLine(0); + + // Make sure next skips the unselectable separator. + autofill_popup_controller_->SelectNextLine(); + EXPECT_EQ(2, autofill_popup_controller_->selected_line()); + + // Make sure previous skips the unselectable separator. + autofill_popup_controller_->SelectPreviousLine(); + EXPECT_EQ(0, autofill_popup_controller_->selected_line()); +} diff --git a/chrome/browser/ui/autofill/autofill_popup_view.cc b/chrome/browser/ui/autofill/autofill_popup_view.cc new file mode 100644 index 0000000..24e4a30 --- /dev/null +++ b/chrome/browser/ui/autofill/autofill_popup_view.cc @@ -0,0 +1,22 @@ +// Copyright (c) 2012 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 "base/logging.h" +#include "chrome/browser/ui/autofill/autofill_popup_view.h" + +const size_t AutofillPopupView::kBorderThickness = 1; +const size_t AutofillPopupView::kIconPadding = 5; +const size_t AutofillPopupView::kEndPadding = 3; +const size_t AutofillPopupView::kDeleteIconHeight = 16; +const size_t AutofillPopupView::kDeleteIconWidth = 16; +const size_t AutofillPopupView::kAutofillIconHeight = 16; +const size_t AutofillPopupView::kAutofillIconWidth = 25; + +#if defined(OS_MACOSX) +AutofillPopupView* AutofillPopupView::Create( + AutofillPopupController* controller) { + NOTIMPLEMENTED(); + return NULL; +} +#endif diff --git a/chrome/browser/ui/autofill/autofill_popup_view.h b/chrome/browser/ui/autofill/autofill_popup_view.h new file mode 100644 index 0000000..8b977b5 --- /dev/null +++ b/chrome/browser/ui/autofill/autofill_popup_view.h @@ -0,0 +1,64 @@ +// Copyright (c) 2012 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_UI_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ +#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ + +#include "ui/gfx/native_widget_types.h" + +class AutofillPopupController; + +namespace gfx { +class Rect; +} + +namespace ui { +class KeyEvent; +} + +// The interface for creating and controlling a platform-dependent +// AutofillPopupView. +class AutofillPopupView { + public: + // The size of the border around the entire results popup, in pixels. + static const size_t kBorderThickness; + + // The amount of padding between icons in pixels. + static const size_t kIconPadding; + + // The amount of padding at the end of the popup in pixels. + static const size_t kEndPadding; + + // Height of the delete icon in pixels. + static const size_t kDeleteIconHeight; + + // Width of the delete icon in pixels. + static const size_t kDeleteIconWidth; + + // Height of the Autofill icons in pixels. + static const size_t kAutofillIconHeight; + + // Width of the Autofill icons in pixels. + static const size_t kAutofillIconWidth; + + // Displays the Autofill popup and fills it in with data from the controller. + virtual void Show() = 0; + + // Hides the popup from view. This will cause the popup to be deleted. + virtual void Hide() = 0; + + // Invalidates the given row and redraw it. + virtual void InvalidateRow(size_t row) = 0; + + // Refreshes the position of the popup. + virtual void UpdateBoundsAndRedrawPopup() = 0; + + // Factory function for creating the view. + static AutofillPopupView* Create(AutofillPopupController* controller); + + protected: + virtual ~AutofillPopupView() {} +}; + +#endif // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ diff --git a/chrome/browser/ui/gtk/autofill/autofill_external_delegate_gtk.cc b/chrome/browser/ui/gtk/autofill/autofill_external_delegate_gtk.cc deleted file mode 100644 index fe134ec..0000000 --- a/chrome/browser/ui/gtk/autofill/autofill_external_delegate_gtk.cc +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2012 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/ui/gtk/autofill/autofill_external_delegate_gtk.h" - -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h" -#include "chrome/browser/ui/gtk/gtk_theme_service.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" - -void AutofillExternalDelegate::CreateForWebContentsAndManager( - content::WebContents* web_contents, - AutofillManager* autofill_manager) { - if (FromWebContents(web_contents)) - return; - - web_contents->SetUserData( - UserDataKey(), - new AutofillExternalDelegateGtk(web_contents, autofill_manager)); -} - -AutofillExternalDelegateGtk::AutofillExternalDelegateGtk( - content::WebContents* web_contents, - AutofillManager* autofill_manager) - : AutofillExternalDelegate(web_contents, autofill_manager), - event_handler_id_(0) { - tab_native_view_ = web_contents->GetView()->GetNativeView(); -} - -AutofillExternalDelegateGtk::~AutofillExternalDelegateGtk() { -} - -void AutofillExternalDelegateGtk::HideAutofillPopupInternal() { - if (!view_.get()) - return; - - view_->Hide(); - view_.reset(); - - GtkWidget* toplevel = gtk_widget_get_toplevel(tab_native_view_); - if (g_signal_handler_is_connected(toplevel, event_handler_id_)) - g_signal_handler_disconnect(toplevel, event_handler_id_); -} - -void AutofillExternalDelegateGtk::ApplyAutofillSuggestions( - const std::vector<string16>& autofill_values, - const std::vector<string16>& autofill_labels, - const std::vector<string16>& autofill_icons, - const std::vector<int>& autofill_unique_ids) { - view_->Show(autofill_values, - autofill_labels, - autofill_icons, - autofill_unique_ids); -} - -void AutofillExternalDelegateGtk::CreatePopupForElement( - const gfx::Rect& element_bounds) { - content::WebContents* contents = web_contents(); - Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); - view_.reset(new AutofillPopupViewGtk(contents, - GtkThemeService::GetFrom(profile), - this, - element_bounds, - tab_native_view_)); - - GtkWidget* toplevel = gtk_widget_get_toplevel(tab_native_view_); - if (!g_signal_handler_is_connected(toplevel, event_handler_id_)) { - event_handler_id_ = g_signal_connect( - toplevel, - "focus-out-event", - G_CALLBACK(HandleViewFocusOutThunk), - this); - } -} - -gboolean AutofillExternalDelegateGtk::HandleViewFocusOut(GtkWidget* sender, - GdkEventFocus* event) { - if (!popup_visible()) - return FALSE; - - HideAutofillPopup(); - - return TRUE; -} diff --git a/chrome/browser/ui/gtk/autofill/autofill_external_delegate_gtk.h b/chrome/browser/ui/gtk/autofill/autofill_external_delegate_gtk.h deleted file mode 100644 index 8b39994..0000000 --- a/chrome/browser/ui/gtk/autofill/autofill_external_delegate_gtk.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2012 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_UI_GTK_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_GTK_H_ -#define CHROME_BROWSER_UI_GTK_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_GTK_H_ - -#include <gtk/gtk.h> - -#include "base/memory/scoped_ptr.h" -#include "chrome/browser/autofill/autofill_external_delegate.h" -#include "ui/base/gtk/gtk_signal.h" -#include "ui/gfx/native_widget_types.h" - -class AutofillPopupViewGtk; - -class AutofillExternalDelegateGtk : public AutofillExternalDelegate { - public: - AutofillExternalDelegateGtk(content::WebContents* web_contents, - AutofillManager* autofill_manager); - - virtual ~AutofillExternalDelegateGtk(); - - protected: - // AutofillExternalDelegate implementations. - virtual void HideAutofillPopupInternal() OVERRIDE; - virtual void ApplyAutofillSuggestions( - const std::vector<string16>& autofill_values, - const std::vector<string16>& autofill_labels, - const std::vector<string16>& autofill_icons, - const std::vector<int>& autofill_unique_ids) OVERRIDE; - virtual void CreatePopupForElement(const gfx::Rect& element_bounds) OVERRIDE; - - private: - // Create a valid view to display the autofill results if one doesn't - // currently exist. - void CreateViewIfNeeded(); - - CHROMEGTK_CALLBACK_1(AutofillExternalDelegateGtk, gboolean, - HandleViewFocusOut, GdkEventFocus*); - - // Unlike in the Views implementation, the popup is always destroyed when - // this class is. - scoped_ptr<AutofillPopupViewGtk> view_; - - gfx::NativeView tab_native_view_; // Weak reference. - - // The handler value for the focus out event, allows us to block and unblock - // it as needed. - gulong event_handler_id_; - - DISALLOW_COPY_AND_ASSIGN(AutofillExternalDelegateGtk); -}; - -#endif // CHROME_BROWSER_UI_GTK_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_GTK_H_ diff --git a/chrome/browser/ui/gtk/autofill/autofill_external_delegate_gtk_browsertest.cc b/chrome/browser/ui/gtk/autofill/autofill_external_delegate_gtk_browsertest.cc deleted file mode 100644 index ceef438..0000000 --- a/chrome/browser/ui/gtk/autofill/autofill_external_delegate_gtk_browsertest.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2012 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/ui/gtk/autofill/autofill_external_delegate_gtk.h" - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "chrome/browser/autofill/autofill_manager.h" -#include "chrome/browser/autofill/test_autofill_external_delegate.h" -#include "chrome/browser/ui/browser_commands.h" -#include "chrome/browser/ui/browser_tabstrip.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class MockAutofillExternalDelegateGtk : public AutofillExternalDelegateGtk { - public: - explicit MockAutofillExternalDelegateGtk(content::WebContents* web_contents) - : AutofillExternalDelegateGtk( - web_contents, - AutofillManager::FromWebContents(web_contents)) {} - ~MockAutofillExternalDelegateGtk() {} - - virtual void ClearPreviewedForm() OVERRIDE {} - - private: - DISALLOW_COPY_AND_ASSIGN(MockAutofillExternalDelegateGtk); -}; - -} // namespace - -class AutofillExternalDelegateGtkBrowserTest : public InProcessBrowserTest { - public: - AutofillExternalDelegateGtkBrowserTest() {} - virtual ~AutofillExternalDelegateGtkBrowserTest() {} - - virtual void SetUpOnMainThread() OVERRIDE { - web_contents_ = chrome::GetActiveWebContents(browser()); - ASSERT_TRUE(web_contents_ != NULL); - - autofill_external_delegate_.reset( - new MockAutofillExternalDelegateGtk(web_contents_)); - } - - protected: - content::WebContents* web_contents_; - scoped_ptr<MockAutofillExternalDelegateGtk> autofill_external_delegate_; - - private: - DISALLOW_COPY_AND_ASSIGN(AutofillExternalDelegateGtkBrowserTest); -}; - -// Ensure that the Autofill code doesn't crash if the window is closed while -// the Autofill popup is still visible. See http://crbug.com/160866 -IN_PROC_BROWSER_TEST_F(AutofillExternalDelegateGtkBrowserTest, - CloseBrowserWithPopupOpen) { - autofill::GenerateTestAutofillPopup(autofill_external_delegate_.get()); - - chrome::CloseWindow(browser()); -} diff --git a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc index d927583..c231156 100644 --- a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc +++ b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc @@ -2,23 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "autofill_popup_view_gtk.h" +#include "chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h" #include <gdk/gdkkeysyms.h> #include "base/i18n/rtl.h" #include "base/logging.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/autofill/autofill_external_delegate.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller.h" #include "chrome/browser/ui/gtk/gtk_util.h" -#include "chrome/browser/ui/gtk/gtk_theme_service.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" #include "grit/ui_resources.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h" #include "ui/base/gtk/gtk_compat.h" #include "ui/base/gtk/gtk_hig_constants.h" #include "ui/base/gtk/gtk_windowing.h" +#include "ui/base/resource/resource_bundle.h" #include "ui/gfx/image/image.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/pango_util.h" @@ -40,17 +38,9 @@ gfx::Rect GetWindowRect(GdkWindow* window) { } // namespace AutofillPopupViewGtk::AutofillPopupViewGtk( - content::WebContents* web_contents, - GtkThemeService* theme_service, - AutofillExternalDelegate* external_delegate, - const gfx::Rect& element_bounds, - GtkWidget* parent) - : AutofillPopupView(web_contents, external_delegate, element_bounds), - parent_(parent), - window_(gtk_window_new(GTK_WINDOW_POPUP)), - theme_service_(theme_service), - render_view_host_(web_contents->GetRenderViewHost()) { - CHECK(parent != NULL); + AutofillPopupController* controller) + : controller_(controller), + window_(gtk_window_new(GTK_WINDOW_POPUP)) { gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); gtk_widget_set_app_paintable(window_, TRUE); gtk_widget_set_double_buffered(window_, TRUE); @@ -74,47 +64,44 @@ AutofillPopupViewGtk::AutofillPopupViewGtk( } AutofillPopupViewGtk::~AutofillPopupViewGtk() { + controller_->ViewDestroyed(); g_object_unref(layout_); gtk_widget_destroy(window_); } void AutofillPopupViewGtk::Hide() { - render_view_host_->RemoveKeyboardListener(this); - - gtk_widget_hide(window_); + delete this; } -void AutofillPopupViewGtk::ShowInternal() { +void AutofillPopupViewGtk::Show() { SetInitialBounds(); UpdateBoundsAndRedrawPopup(); - render_view_host_->AddKeyboardListener(this); - gtk_widget_show(window_); - GtkWidget* toplevel = gtk_widget_get_toplevel(parent_); - CHECK(gtk_widget_is_toplevel(toplevel)); - ui::StackPopupWindow(window_, toplevel); + GtkWidget* parent_window = + gtk_widget_get_toplevel(controller_->container_view()); + ui::StackPopupWindow(window_, parent_window); } void AutofillPopupViewGtk::InvalidateRow(size_t row) { - GdkRectangle row_rect = GetRectForRow( + GdkRectangle row_rect = controller_->GetRectForRow( row, - popup_bounds().width()).ToGdkRectangle(); + controller_->popup_bounds().width()).ToGdkRectangle(); GdkWindow* gdk_window = gtk_widget_get_window(window_); gdk_window_invalidate_rect(gdk_window, &row_rect, FALSE); } -void AutofillPopupViewGtk::UpdateBoundsAndRedrawPopupInternal() { +void AutofillPopupViewGtk::UpdateBoundsAndRedrawPopup() { gtk_widget_set_size_request(window_, - popup_bounds().width(), - popup_bounds().height()); + controller_->popup_bounds().width(), + controller_->popup_bounds().height()); gtk_window_move(GTK_WINDOW(window_), - popup_bounds().x(), - popup_bounds().y()); + controller_->popup_bounds().x(), + controller_->popup_bounds().y()); GdkWindow* gdk_window = gtk_widget_get_window(window_); - GdkRectangle popup_rect = popup_bounds().ToGdkRectangle(); + GdkRectangle popup_rect = controller_->popup_bounds().ToGdkRectangle(); if (gdk_window != NULL) gdk_window_invalidate_rect(gdk_window, &popup_rect, FALSE); } @@ -125,7 +112,7 @@ gboolean AutofillPopupViewGtk::HandleButtonRelease(GtkWidget* widget, if (event->button != 1) return FALSE; - AcceptSelectedPosition(event->x, event->y); + controller_->AcceptSelectedPosition(event->x, event->y); return TRUE; } @@ -149,16 +136,18 @@ gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget, SetupLayout(window_rect); - for (size_t i = 0; i < autofill_values().size(); ++i) { - gfx::Rect line_rect = GetRectForRow(i, window_rect.width()); + for (size_t i = 0; i < controller_->autofill_values().size(); ++i) { + gfx::Rect line_rect = controller_->GetRectForRow(i, window_rect.width()); // Only repaint and layout damaged lines. if (!line_rect.Intersects(damage_rect)) continue; - if (autofill_unique_ids()[i] == WebAutofillClient::MenuItemIDSeparator) + if (controller_->autofill_unique_ids()[i] == + WebAutofillClient::MenuItemIDSeparator) { DrawSeparator(cr, line_rect); - else + } else { DrawAutofillEntry(cr, i, line_rect); + } } cairo_destroy(cr); @@ -168,49 +157,18 @@ gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget, gboolean AutofillPopupViewGtk::HandleLeave(GtkWidget* widget, GdkEventCrossing* event) { - ClearSelectedLine(); + controller_->ClearSelectedLine(); return FALSE; } gboolean AutofillPopupViewGtk::HandleMotion(GtkWidget* widget, GdkEventMotion* event) { - SetSelectedPosition(event->x, event->y); + controller_->SetSelectedPosition(event->x, event->y); return TRUE; } -bool AutofillPopupViewGtk::HandleKeyPressEvent(GdkEventKey* event) { - // Filter modifier to only include accelerator modifiers. - guint modifier = event->state & gtk_accelerator_get_default_mod_mask(); - - switch (event->keyval) { - case GDK_Up: - SelectPreviousLine(); - return true; - case GDK_Down: - SelectNextLine(); - return true; - case GDK_Page_Up: - SetSelectedLine(0); - return true; - case GDK_Page_Down: - SetSelectedLine(autofill_values().size() - 1); - return true; - case GDK_Escape: - external_delegate()->HideAutofillPopup(); - return true; - case GDK_Delete: - case GDK_KP_Delete: - return (modifier == GDK_SHIFT_MASK) && RemoveSelectedLine(); - case GDK_Return: - case GDK_KP_Enter: - return AcceptSelectedLine(); - } - - return false; -} - void AutofillPopupViewGtk::SetupLayout(const gfx::Rect& window_rect) { pango_layout_set_width(layout_, window_rect.width() * PANGO_SCALE); pango_layout_set_height(layout_, window_rect.height() * PANGO_SCALE); @@ -255,7 +213,7 @@ void AutofillPopupViewGtk::DrawSeparator(cairo_t* cairo_context, void AutofillPopupViewGtk::DrawAutofillEntry(cairo_t* cairo_context, size_t index, const gfx::Rect& entry_rect) { - if (selected_line() == static_cast<int>(index)) { + if (controller_->selected_line() == static_cast<int>(index)) { gdk_cairo_set_source_color(cairo_context, &kHoveredBackgroundColor); cairo_rectangle(cairo_context, entry_rect.x(), entry_rect.y(), entry_rect.width(), entry_rect.height()); @@ -263,14 +221,19 @@ void AutofillPopupViewGtk::DrawAutofillEntry(cairo_t* cairo_context, } // Draw the value. - SetLayoutText(autofill_values()[index], value_font(), kValueTextColor); - int value_text_width = value_font().GetStringWidth(autofill_values()[index]); + SetLayoutText(controller_->autofill_values()[index], + controller_->value_font(), + kValueTextColor); + int value_text_width = controller_->value_font().GetStringWidth( + controller_->autofill_values()[index]); // Center the text within the line. - int row_height = GetRowHeightFromId(autofill_unique_ids()[index]); + int row_height = controller_->GetRowHeightFromId( + controller_->autofill_unique_ids()[index]); int value_content_y = std::max( entry_rect.y(), - entry_rect.y() + ((row_height - value_font().GetHeight()) / 2)); + entry_rect.y() + + (row_height - controller_->value_font().GetHeight()) / 2); bool is_rtl = base::i18n::IsRTL(); int value_content_x = is_rtl ? @@ -284,15 +247,19 @@ void AutofillPopupViewGtk::DrawAutofillEntry(cairo_t* cairo_context, // Use this to figure out where all the other Autofill items should be placed. int x_align_left = is_rtl ? kEndPadding : entry_rect.width() - kEndPadding; + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + // Draw the delete icon, if one is needed. - if (CanDelete(autofill_unique_ids()[index])) { + if (controller_->CanDelete(controller_->autofill_unique_ids()[index])) { x_align_left += is_rtl ? 0 : -kDeleteIconWidth; gfx::Image delete_icon; - if (static_cast<int>(index) == selected_line() && delete_icon_selected()) - delete_icon = theme_service_->GetImageNamed(IDR_CLOSE_BAR_H); - else - delete_icon = theme_service_->GetImageNamed(IDR_CLOSE_BAR); + if (static_cast<int>(index) == controller_->selected_line() && + controller_->delete_icon_hovered()) { + delete_icon = rb.GetImageNamed(IDR_CLOSE_BAR_H); + } else { + delete_icon = rb.GetImageNamed(IDR_CLOSE_BAR); + } // TODO(csharp): Create a custom resource for the delete icon. // http://crbug.com/131801 @@ -311,8 +278,9 @@ void AutofillPopupViewGtk::DrawAutofillEntry(cairo_t* cairo_context, } // Draw the Autofill icon, if one exists - if (!autofill_icons()[index].empty()) { - int icon = GetIconResourceID(autofill_icons()[index]); + if (!controller_->autofill_icons()[index].empty()) { + int icon = + controller_->GetIconResourceID(controller_->autofill_icons()[index]); DCHECK_NE(-1, icon); int icon_y = entry_rect.y() + (row_height - kAutofillIconHeight) / 2; @@ -321,7 +289,7 @@ void AutofillPopupViewGtk::DrawAutofillEntry(cairo_t* cairo_context, cairo_save(cairo_context); gtk_util::DrawFullImage(cairo_context, window_, - theme_service_->GetImageNamed(icon), + rb.GetImageNamed(icon), x_align_left, icon_y); cairo_restore(cairo_context); @@ -330,14 +298,19 @@ void AutofillPopupViewGtk::DrawAutofillEntry(cairo_t* cairo_context, } // Draw the label text. - SetLayoutText(autofill_labels()[index], label_font(), kLabelTextColor); - x_align_left += - is_rtl ? 0 : -label_font().GetStringWidth(autofill_labels()[index]); + SetLayoutText(controller_->autofill_labels()[index], + controller_->label_font(), + kLabelTextColor); + if (!is_rtl) { + x_align_left -= controller_->label_font().GetStringWidth( + controller_->autofill_labels()[index]); + } // Center the text within the line. int label_content_y = std::max( entry_rect.y(), - entry_rect.y() + ((row_height - label_font().GetHeight()) / 2)); + entry_rect.y() + + (row_height - controller_->label_font().GetHeight()) / 2); cairo_save(cairo_context); cairo_move_to(cairo_context, x_align_left, label_content_y); @@ -346,29 +319,37 @@ void AutofillPopupViewGtk::DrawAutofillEntry(cairo_t* cairo_context, } void AutofillPopupViewGtk::SetInitialBounds() { - gint origin_x, origin_y; - gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y); - - GdkScreen* screen = gtk_widget_get_screen(parent_); + GdkScreen* screen = + gtk_widget_get_screen(GTK_WIDGET(controller_->container_view())); gint screen_height = gdk_screen_get_height(screen); - int bottom_of_field = origin_y + element_bounds().y() + - element_bounds().height(); - int popup_height = GetPopupRequiredHeight(); + int x = 0; + int y = 0; + gdk_window_get_origin( + gtk_widget_get_window(controller_->container_view()), &x, &y); + + int bottom_of_field = y + controller_->element_bounds().bottom(); + int popup_height = controller_->GetPopupRequiredHeight(); // Find the correct top position of the popup so that is doesn't go off // the screen. int top_of_popup = 0; if (screen_height < bottom_of_field + popup_height) { // The popup must appear above the field. - top_of_popup = origin_y + element_bounds().y() - popup_height; + top_of_popup = y + controller_->element_bounds().y() - popup_height; } else { // The popup can appear below the field. top_of_popup = bottom_of_field; } - SetPopupBounds(gfx::Rect(origin_x + element_bounds().x(), - top_of_popup, - GetPopupRequiredWidth(), - popup_height)); + controller_->SetPopupBounds(gfx::Rect( + x + controller_->element_bounds().x(), + top_of_popup, + controller_->GetPopupRequiredWidth(), + popup_height)); +} + +AutofillPopupView* AutofillPopupView::Create( + AutofillPopupController* controller) { + return new AutofillPopupViewGtk(controller); } diff --git a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h index 261b96f..24664c5 100644 --- a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h +++ b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h @@ -8,12 +8,14 @@ #include <pango/pango.h> #include <vector> -#include "chrome/browser/autofill/autofill_popup_view.h" -#include "content/public/browser/keyboard_listener.h" +#include "base/compiler_specific.h" +#include "base/string16.h" +#include "chrome/browser/ui/autofill/autofill_popup_view.h" #include "ui/base/glib/glib_integers.h" #include "ui/base/gtk/gtk_signal.h" +#include "ui/gfx/font.h" -class GtkThemeService; +class AutofillPopupController; class Profile; namespace content { @@ -32,26 +34,20 @@ typedef struct _GdkEventMotion GdkEventMotion; typedef struct _GdkColor GdkColor; typedef struct _GtkWidget GtkWidget; -class AutofillPopupViewGtk : public AutofillPopupView, - public KeyboardListener { +// Gtk implementation for AutofillPopupView interface. +class AutofillPopupViewGtk : public AutofillPopupView { public: - AutofillPopupViewGtk(content::WebContents* web_contents, - GtkThemeService* theme_service, - AutofillExternalDelegate* external_delegate, - const gfx::Rect& element_bounds, - GtkWidget* parent); + explicit AutofillPopupViewGtk(AutofillPopupController* controller); + + private: virtual ~AutofillPopupViewGtk(); // AutofillPopupView implementation. virtual void Hide() OVERRIDE; - - protected: - // AutofillPopupView implementations. - virtual void ShowInternal() OVERRIDE; + virtual void Show() OVERRIDE; virtual void InvalidateRow(size_t row) OVERRIDE; - virtual void UpdateBoundsAndRedrawPopupInternal() OVERRIDE; + virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; - private: CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleButtonRelease, GdkEventButton*); CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleExpose, @@ -61,9 +57,6 @@ class AutofillPopupViewGtk : public AutofillPopupView, CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleMotion, GdkEventMotion*); - // KeyboardListener implementation. - virtual bool HandleKeyPressEvent(GdkEventKey* event) OVERRIDE; - // Set up the pango layout to display the autofill results. void SetupLayout(const gfx::Rect& window_rect); @@ -85,12 +78,10 @@ class AutofillPopupViewGtk : public AutofillPopupView, // of it. void SetInitialBounds(); - GtkWidget* parent_; // Weak reference. - GtkWidget* window_; // Strong reference. - PangoLayout* layout_; // Strong reference - GtkThemeService* theme_service_; + AutofillPopupController* controller_; // Weak reference. - content::RenderViewHost* render_view_host_; // Weak reference. + GtkWidget* window_; // Strong reference. + PangoLayout* layout_; // Strong reference. DISALLOW_COPY_AND_ASSIGN(AutofillPopupViewGtk); }; diff --git a/chrome/browser/ui/views/autofill/autofill_external_delegate_views.cc b/chrome/browser/ui/views/autofill/autofill_external_delegate_views.cc deleted file mode 100644 index ebbb77f..0000000 --- a/chrome/browser/ui/views/autofill/autofill_external_delegate_views.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2012 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/ui/views/autofill/autofill_external_delegate_views.h" - -#include "chrome/browser/ui/views/autofill/autofill_popup_view_views.h" - -void AutofillExternalDelegate::CreateForWebContentsAndManager( - content::WebContents* web_contents, - AutofillManager* autofill_manager) { - if (FromWebContents(web_contents)) - return; - - web_contents->SetUserData( - UserDataKey(), - new AutofillExternalDelegateViews(web_contents, autofill_manager)); -} - -AutofillExternalDelegateViews::AutofillExternalDelegateViews( - content::WebContents* web_contents, - AutofillManager* autofill_manager) - : AutofillExternalDelegate(web_contents, autofill_manager), - popup_view_(NULL) { -} - -AutofillExternalDelegateViews::~AutofillExternalDelegateViews() { - if (popup_view_) { - popup_view_->ClearExternalDelegate(); - } -} - -void AutofillExternalDelegateViews::InvalidateView() { - popup_view_ = NULL; - HideAutofillPopup(); -} - -void AutofillExternalDelegateViews::HideAutofillPopupInternal() { - if (!popup_view_) - return; - - popup_view_->Hide(); - popup_view_ = NULL; -} - -void AutofillExternalDelegateViews::CreatePopupForElement( - const gfx::Rect& element_bounds) { - DCHECK(!popup_view_); - popup_view_ = new AutofillPopupViewViews( - web_contents(), this, element_bounds); -} - -void AutofillExternalDelegateViews::ApplyAutofillSuggestions( - const std::vector<string16>& autofill_values, - const std::vector<string16>& autofill_labels, - const std::vector<string16>& autofill_icons, - const std::vector<int>& autofill_unique_ids) { - popup_view_->Show(autofill_values, - autofill_labels, - autofill_icons, - autofill_unique_ids); -} diff --git a/chrome/browser/ui/views/autofill/autofill_external_delegate_views.h b/chrome/browser/ui/views/autofill/autofill_external_delegate_views.h deleted file mode 100644 index 26b66f2..0000000 --- a/chrome/browser/ui/views/autofill/autofill_external_delegate_views.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2012 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_UI_VIEWS_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_VIEWS_H_ -#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_VIEWS_H_ - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "chrome/browser/autofill/autofill_external_delegate.h" - -class AutofillPopupViewViews; - -// The View specific implementations of the AutofillExternalDelegate, -// handling the communication between the Autofill and Autocomplete -// selection and the popup that shows the values. -class AutofillExternalDelegateViews : public AutofillExternalDelegate { - public: - AutofillExternalDelegateViews(content::WebContents* web_contents, - AutofillManager* autofill_manager); - - virtual ~AutofillExternalDelegateViews(); - - // Used by the popup view to indicate it has been destroyed. - void InvalidateView(); - - protected: - AutofillPopupViewViews* popup_view() { return popup_view_; } - - // AutofillExternalDelegate implementation. - // Make protected to allow tests to override. - virtual void HideAutofillPopupInternal() OVERRIDE; - virtual void CreatePopupForElement(const gfx::Rect& element_bounds) OVERRIDE; - - private: - // AutofillExternalDelegate implementation. - virtual void ApplyAutofillSuggestions( - const std::vector<string16>& autofill_values, - const std::vector<string16>& autofill_labels, - const std::vector<string16>& autofill_icons, - const std::vector<int>& autofill_unique_ids) OVERRIDE; - - // We use a raw pointer here because even though we usually create the view, - // its widget handles deleting it (which means it may outlive this object). - AutofillPopupViewViews* popup_view_; - - DISALLOW_COPY_AND_ASSIGN(AutofillExternalDelegateViews); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_VIEWS_H_ diff --git a/chrome/browser/ui/views/autofill/autofill_external_delegate_views_browsertest.cc b/chrome/browser/ui/views/autofill/autofill_external_delegate_views_browsertest.cc deleted file mode 100644 index 0837349..0000000 --- a/chrome/browser/ui/views/autofill/autofill_external_delegate_views_browsertest.cc +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2012 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/ui/views/autofill/autofill_external_delegate_views.h" - -#include "base/memory/scoped_ptr.h" -#include "chrome/browser/autofill/autofill_manager.h" -#include "chrome/browser/autofill/test_autofill_external_delegate.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_tabstrip.h" -#include "chrome/browser/ui/views/autofill/autofill_popup_view_views.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "content/public/browser/navigation_controller.h" -#include "content/public/browser/notification_types.h" -#include "content/public/common/url_constants.h" -#include "content/public/test/test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/views/widget/widget.h" - -namespace { - -class MockAutofillExternalDelegateViews : public AutofillExternalDelegateViews { - public: - explicit MockAutofillExternalDelegateViews(content::WebContents* web_contents) - : AutofillExternalDelegateViews( - web_contents, - AutofillManager::FromWebContents(web_contents)), - popup_hidden_(false) {} - ~MockAutofillExternalDelegateViews() {} - - void HideAutofillPopupInternal() OVERRIDE { - popup_hidden_ = true; - AutofillExternalDelegateViews::HideAutofillPopupInternal(); - } - - AutofillPopupViewViews* popup_view() { - return AutofillExternalDelegateViews::popup_view(); - } - - virtual void ClearPreviewedForm() OVERRIDE {} - - bool popup_hidden_; -}; - -} // namespace - -class AutofillExternalDelegateViewsBrowserTest : public InProcessBrowserTest { - public: - AutofillExternalDelegateViewsBrowserTest() {} - virtual ~AutofillExternalDelegateViewsBrowserTest() {} - - virtual void SetUpOnMainThread() OVERRIDE { - web_contents_ = chrome::GetActiveWebContents(browser()); - ASSERT_TRUE(web_contents_ != NULL); - - autofill_external_delegate_.reset( - new MockAutofillExternalDelegateViews(web_contents_)); - } - - protected: - content::WebContents* web_contents_; - scoped_ptr<MockAutofillExternalDelegateViews> autofill_external_delegate_; -}; - -IN_PROC_BROWSER_TEST_F(AutofillExternalDelegateViewsBrowserTest, - OpenAndClosePopup) { - autofill::GenerateTestAutofillPopup(autofill_external_delegate_.get()); - - autofill_external_delegate_->HideAutofillPopup(); - EXPECT_TRUE(autofill_external_delegate_->popup_hidden_); -} - -// See http://crbug.com/164019 -#if !defined(USE_AURA) -IN_PROC_BROWSER_TEST_F(AutofillExternalDelegateViewsBrowserTest, - CloseWidgetAndNoLeaking) { - autofill::GenerateTestAutofillPopup(autofill_external_delegate_.get()); - // Delete the widget to ensure that the external delegate can handle the - // popup getting deleted elsewhere. - views::Widget* popup_widget = - autofill_external_delegate_->popup_view()->GetWidget(); - popup_widget->CloseNow(); - - EXPECT_TRUE(autofill_external_delegate_->popup_hidden_); -} -#endif // !defined(USE_AURA) - -IN_PROC_BROWSER_TEST_F(AutofillExternalDelegateViewsBrowserTest, - HandlePopupClosingAndChangingPages) { - autofill::GenerateTestAutofillPopup(autofill_external_delegate_.get()); - - // Close popup. - autofill_external_delegate_->HideAutofillPopup(); - - // Navigate to a new page - content::WindowedNotificationObserver observer( - content::NOTIFICATION_NAV_ENTRY_COMMITTED, - content::Source<content::NavigationController>( - &(web_contents_->GetController()))); - browser()->OpenURL(content::OpenURLParams( - GURL(chrome::kAboutBlankURL), content::Referrer(), - CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false)); - observer.Wait(); -} diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc index 81845e2..224ca81 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc +++ b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc @@ -2,12 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "autofill_popup_view_views.h" +#include "chrome/browser/ui/views/autofill/autofill_popup_view_views.h" -#include "chrome/browser/ui/views/autofill/autofill_external_delegate_views.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller.h" #include "grit/ui_resources.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h" #include "ui/base/keycodes/keyboard_codes.h" @@ -24,6 +21,7 @@ using WebKit::WebAutofillClient; namespace { + const SkColor kBorderColor = SkColorSetARGB(0xFF, 0xC7, 0xCA, 0xCE); const SkColor kHoveredBackgroundColor = SkColorSetARGB(0xFF, 0xCD, 0xCD, 0xCD); const SkColor kLabelTextColor = SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F); @@ -33,50 +31,49 @@ const SkColor kValueTextColor = SkColorSetARGB(0xFF, 0x00, 0x00, 0x00); } // namespace AutofillPopupViewViews::AutofillPopupViewViews( - content::WebContents* web_contents, - AutofillExternalDelegateViews* external_delegate, - const gfx::Rect& element_bounds) - : AutofillPopupView(web_contents, external_delegate, element_bounds), - external_delegate_(external_delegate), - web_contents_(web_contents) { -} + AutofillPopupController* controller) + : controller_(controller), + observing_widget_(NULL) {} AutofillPopupViewViews::~AutofillPopupViewViews() { - external_delegate_->InvalidateView(); + if (observing_widget_) + observing_widget_->RemoveObserver(this); + + controller_->ViewDestroyed(); } void AutofillPopupViewViews::Hide() { - if (GetWidget()) + if (GetWidget()) { + // This deletes |this|. GetWidget()->Close(); - web_contents_->GetRenderViewHost()->RemoveKeyboardListener(this); - - views::Widget* browser_widget = - views::Widget::GetTopLevelWidgetForNativeView( - web_contents_->GetView()->GetTopLevelNativeWindow()); - browser_widget->RemoveObserver(this); + } else { + delete this; + } } void AutofillPopupViewViews::OnPaint(gfx::Canvas* canvas) { canvas->DrawColor(kPopupBackground); OnPaintBorder(canvas); - for (size_t i = 0; i < autofill_values().size(); ++i) { - gfx::Rect line_rect = GetRectForRow(i, width()); + for (size_t i = 0; i < controller_->autofill_values().size(); ++i) { + gfx::Rect line_rect = controller_->GetRectForRow(i, width()); - if (autofill_unique_ids()[i] == WebAutofillClient::MenuItemIDSeparator) + if (controller_->autofill_unique_ids()[i] == + WebAutofillClient::MenuItemIDSeparator) { canvas->DrawRect(line_rect, kLabelTextColor); - else + } else { DrawAutofillEntry(canvas, i, line_rect); + } } } void AutofillPopupViewViews::OnMouseCaptureLost() { - ClearSelectedLine(); + controller_->ClearSelectedLine(); } bool AutofillPopupViewViews::OnMouseDragged(const ui::MouseEvent& event) { if (HitTestPoint(gfx::Point(event.x(), event.y()))) { - SetSelectedPosition(event.x(), event.y()); + controller_->SetSelectedPosition(event.x(), event.y()); // We must return true in order to get future OnMouseDragged and // OnMouseReleased events. @@ -84,16 +81,16 @@ bool AutofillPopupViewViews::OnMouseDragged(const ui::MouseEvent& event) { } // If we move off of the popup, we lose the selection. - ClearSelectedLine(); + controller_->ClearSelectedLine(); return false; } void AutofillPopupViewViews::OnMouseExited(const ui::MouseEvent& event) { - ClearSelectedLine(); + controller_->ClearSelectedLine(); } void AutofillPopupViewViews::OnMouseMoved(const ui::MouseEvent& event) { - SetSelectedPosition(event.x(), event.y()); + controller_->SetSelectedPosition(event.x(), event.y()); } bool AutofillPopupViewViews::OnMousePressed(const ui::MouseEvent& event) { @@ -105,42 +102,16 @@ void AutofillPopupViewViews::OnMouseReleased(const ui::MouseEvent& event) { // We only care about the left click. if (event.IsOnlyLeftMouseButton() && HitTestPoint(gfx::Point(event.x(), event.y()))) - AcceptSelectedPosition(event.x(), event.y()); + controller_->AcceptSelectedPosition(event.x(), event.y()); } void AutofillPopupViewViews::OnWidgetBoundsChanged( views::Widget* widget, const gfx::Rect& new_bounds) { - external_delegate()->HideAutofillPopup(); + Hide(); } -bool AutofillPopupViewViews::HandleKeyPressEvent(ui::KeyEvent* event) { - switch (event->key_code()) { - case ui::VKEY_UP: - SelectPreviousLine(); - return true; - case ui::VKEY_DOWN: - SelectNextLine(); - return true; - case ui::VKEY_PRIOR: - SetSelectedLine(0); - return true; - case ui::VKEY_NEXT: - SetSelectedLine(autofill_values().size() - 1); - return true; - case ui::VKEY_ESCAPE: - external_delegate()->HideAutofillPopup(); - return true; - case ui::VKEY_DELETE: - return event->IsShiftDown() && RemoveSelectedLine(); - case ui::VKEY_RETURN: - return AcceptSelectedLine(); - default: - return false; - } -} - -void AutofillPopupViewViews::ShowInternal() { +void AutofillPopupViewViews::Show() { if (!GetWidget()) { // The widget is destroyed by the corresponding NativeWidget, so we use // a weak pointer to hold the reference and don't have to worry about @@ -150,47 +121,37 @@ void AutofillPopupViewViews::ShowInternal() { params.delegate = this; params.can_activate = false; params.transparent = true; - params.parent = web_contents_->GetView()->GetTopLevelNativeWindow(); + params.parent = controller_->container_view(); widget->Init(params); widget->SetContentsView(this); widget->Show(); - gfx::Rect client_area; - web_contents_->GetContainerBounds(&client_area); - widget->SetBounds(client_area); - - // Setup an observer to check for when the browser moves or changes size, - // since the popup should always be hidden in those cases. - views::Widget* browser_widget = - views::Widget::GetTopLevelWidgetForNativeView( - web_contents_->GetView()->GetTopLevelNativeWindow()); - browser_widget->AddObserver(this); - // Allow the popup to appear anywhere on the screen, since it may need // to go beyond the bounds of the window. // TODO(csharp): allow the popup to still appear on the border of // two screens. - widget->SetBounds(gfx::Rect(0, - 0, - GetScreenSize().height(), - GetScreenSize().width())); + widget->SetBounds(gfx::Rect(GetScreenSize())); + + // Setup an observer to check for when the browser moves or changes size, + // since the popup should always be hidden in those cases. + observing_widget_ = views::Widget::GetTopLevelWidgetForNativeView( + controller_->container_view()); + observing_widget_->AddObserver(this); } set_border(views::Border::CreateSolidBorder(kBorderThickness, kBorderColor)); SetInitialBounds(); UpdateBoundsAndRedrawPopup(); - - web_contents_->GetRenderViewHost()->AddKeyboardListener(this); } void AutofillPopupViewViews::InvalidateRow(size_t row) { - SchedulePaintInRect(GetRectForRow(row, width())); + SchedulePaintInRect(controller_->GetRectForRow(row, width())); } -void AutofillPopupViewViews::UpdateBoundsAndRedrawPopupInternal() { - SetBoundsRect(popup_bounds()); - SchedulePaintInRect(popup_bounds()); +void AutofillPopupViewViews::UpdateBoundsAndRedrawPopup() { + SetBoundsRect(controller_->popup_bounds()); + SchedulePaintInRect(controller_->popup_bounds()); } void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas, @@ -198,16 +159,17 @@ void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas, const gfx::Rect& entry_rect) { // TODO(csharp): support RTL - if (selected_line() == index) + if (controller_->selected_line() == index) canvas->FillRect(entry_rect, kHoveredBackgroundColor); canvas->DrawStringInt( - autofill_values()[index], - value_font(), + controller_->autofill_values()[index], + controller_->value_font(), kValueTextColor, kEndPadding, entry_rect.y(), - canvas->GetStringWidth(autofill_values()[index], value_font()), + canvas->GetStringWidth(controller_->autofill_values()[index], + controller_->value_font()), entry_rect.height(), gfx::Canvas::TEXT_ALIGN_CENTER); @@ -216,8 +178,9 @@ void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas, // Draw the delete icon, if one is needed. ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - int row_height = GetRowHeightFromId(autofill_unique_ids()[index]); - if (CanDelete(autofill_unique_ids()[index])) { + int row_height = controller_->GetRowHeightFromId( + controller_->autofill_unique_ids()[index]); + if (controller_->CanDelete(controller_->autofill_unique_ids()[index])) { x_align_left -= kDeleteIconWidth; // TODO(csharp): Create a custom resource for the delete icon. @@ -231,10 +194,11 @@ void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas, } // Draw the Autofill icon, if one exists - if (!autofill_icons()[index].empty()) { - int icon = GetIconResourceID(autofill_icons()[index]); + if (!controller_->autofill_icons()[index].empty()) { + int icon = + controller_->GetIconResourceID(controller_->autofill_icons()[index]); DCHECK_NE(-1, icon); - int icon_y = entry_rect.y() + ((row_height - kAutofillIconHeight) / 2); + int icon_y = entry_rect.y() + (row_height - kAutofillIconHeight) / 2; x_align_left -= kAutofillIconWidth; @@ -244,51 +208,53 @@ void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas, } // Draw the label text. - x_align_left -= canvas->GetStringWidth(autofill_labels()[index], - label_font()); + x_align_left -= canvas->GetStringWidth(controller_->autofill_labels()[index], + controller_->label_font()); canvas->DrawStringInt( - autofill_labels()[index], - label_font(), + controller_->autofill_labels()[index], + controller_->label_font(), kLabelTextColor, x_align_left + kEndPadding, entry_rect.y(), - canvas->GetStringWidth(autofill_labels()[index], label_font()), + canvas->GetStringWidth(controller_->autofill_labels()[index], + controller_->label_font()), entry_rect.height(), gfx::Canvas::TEXT_ALIGN_CENTER); } void AutofillPopupViewViews::SetInitialBounds() { - // Find the client area of the contents to find our offset. - gfx::Rect client_area; - web_contents_->GetContainerBounds(&client_area); - - int bottom_of_field = client_area.y() + element_bounds().y() + - element_bounds().height(); - int popup_height = GetPopupRequiredHeight(); + int bottom_of_field = controller_->element_bounds().bottom(); + int popup_height = controller_->GetPopupRequiredHeight(); // Find the correct top position of the popup so that it doesn't go off // the screen. int top_of_popup = 0; if (GetScreenSize().height() < bottom_of_field + popup_height) { // The popup must appear above the field. - top_of_popup = element_bounds().y() - popup_height; + top_of_popup = controller_->element_bounds().y() - popup_height; } else { // The popup can appear below the field. top_of_popup = bottom_of_field; } - SetPopupBounds(gfx::Rect(client_area.x() + element_bounds().x(), - top_of_popup, - GetPopupRequiredWidth(), - popup_height)); + controller_->SetPopupBounds(gfx::Rect( + controller_->element_bounds().x(), + top_of_popup, + controller_->GetPopupRequiredWidth(), + popup_height)); } gfx::Size AutofillPopupViewViews::GetScreenSize() { - gfx::Screen* screen = gfx::Screen::GetScreenFor( - web_contents_->GetView()->GetTopLevelNativeWindow()); - gfx::Display display = screen->GetDisplayNearestPoint( - gfx::Point(element_bounds().x(), element_bounds().y())); + gfx::Screen* screen = + gfx::Screen::GetScreenFor(controller_->container_view()); + gfx::Display display = + screen->GetDisplayNearestPoint(controller_->element_bounds().origin()); return display.GetSizeInPixel(); } + +AutofillPopupView* AutofillPopupView::Create( + AutofillPopupController* controller) { + return new AutofillPopupViewViews(controller); +} diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_views.h b/chrome/browser/ui/views/autofill/autofill_popup_view_views.h index a9dd94f..c37e61b 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_view_views.h +++ b/chrome/browser/ui/views/autofill/autofill_popup_view_views.h @@ -5,35 +5,32 @@ #ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_VIEW_VIEWS_H_ #define CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_VIEW_VIEWS_H_ -#include "chrome/browser/autofill/autofill_popup_view.h" -#include "content/public/browser/keyboard_listener.h" +#include "chrome/browser/ui/autofill/autofill_popup_view.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_observer.h" -class AutofillExternalDelegateViews; +class AutofillPopupController; namespace content { class WebContents; } -// The View Autofill popup implementation. -class AutofillPopupViewViews : public views::WidgetDelegateView, - public AutofillPopupView, - public views::WidgetObserver, - public KeyboardListener { +// Views toolkit implementation for AutofillPopupView. +class AutofillPopupViewViews : public AutofillPopupView, + public views::WidgetDelegateView, + public views::WidgetObserver { public: - AutofillPopupViewViews(content::WebContents* web_contents, - AutofillExternalDelegateViews* external_delegate, - const gfx::Rect& element_bounds); - - // AutofillPopupView implementation. - virtual void Hide() OVERRIDE; + explicit AutofillPopupViewViews(AutofillPopupController* controller); private: - class AutofillPopupWidget; - virtual ~AutofillPopupViewViews(); + // AutofillPopupView implementation. + virtual void Show() OVERRIDE; + virtual void Hide() OVERRIDE; + virtual void InvalidateRow(size_t row) OVERRIDE; + virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; + // views:Views implementation. virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; @@ -47,14 +44,6 @@ class AutofillPopupViewViews : public views::WidgetDelegateView, virtual void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) OVERRIDE; - // KeyboardListener implementation. - virtual bool HandleKeyPressEvent(ui::KeyEvent* event) OVERRIDE; - - // AutofillPopupView implementation. - virtual void ShowInternal() OVERRIDE; - virtual void InvalidateRow(size_t row) OVERRIDE; - virtual void UpdateBoundsAndRedrawPopupInternal() OVERRIDE; - // Draw the given autofill entry in |entry_rect|. void DrawAutofillEntry(gfx::Canvas* canvas, int index, @@ -67,8 +56,10 @@ class AutofillPopupViewViews : public views::WidgetDelegateView, // Get the size of the screen that the popup appears of, in pixels. gfx::Size GetScreenSize(); - AutofillExternalDelegateViews* external_delegate_; // Weak reference. - content::WebContents* web_contents_; // Weak reference. + AutofillPopupController* controller_; // Weak reference. + + // The widget that |this| observes. Weak reference. + views::Widget* observing_widget_; DISALLOW_COPY_AND_ASSIGN(AutofillPopupViewViews); }; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 682d7d8..a5e9683 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -202,8 +202,6 @@ 'browser/autofill/autofill_manager_delegate.h', 'browser/autofill/autofill_metrics.cc', 'browser/autofill/autofill_metrics.h', - 'browser/autofill/autofill_popup_view.cc', - 'browser/autofill/autofill_popup_view.h', 'browser/autofill/autofill_profile.cc', 'browser/autofill/autofill_profile.h', 'browser/autofill/autofill_regex_constants.cc.utf8', diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index a172494..e005f10 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -70,8 +70,6 @@ 'browser/ui/alternate_error_tab_observer.h', 'browser/ui/android/android_about_app_info.cc', 'browser/ui/android/android_about_app_info.h', - 'browser/ui/android/autofill/autofill_external_delegate.cc', - 'browser/ui/android/autofill/autofill_external_delegate.h', 'browser/ui/android/autofill/autofill_popup_view_android.cc', 'browser/ui/android/autofill/autofill_popup_view_android.h', 'browser/ui/android/certificate_viewer_android.cc', @@ -186,6 +184,11 @@ 'browser/ui/autofill/autofill_dialog_controller.h', 'browser/ui/autofill/autofill_dialog_view.cc', 'browser/ui/autofill/autofill_dialog_view.h', + 'browser/ui/autofill/autofill_popup_controller.h', + 'browser/ui/autofill/autofill_popup_controller_impl.cc', + 'browser/ui/autofill/autofill_popup_controller_impl.h', + 'browser/ui/autofill/autofill_popup_view.cc', + 'browser/ui/autofill/autofill_popup_view.h', 'browser/ui/autofill/tab_autofill_manager_delegate.cc', 'browser/ui/autofill/tab_autofill_manager_delegate.h', 'browser/ui/auto_login_info_bar_delegate.cc', @@ -842,8 +845,6 @@ 'browser/ui/gtk/accelerators_gtk.h', 'browser/ui/gtk/action_box_button_gtk.cc', 'browser/ui/gtk/action_box_button_gtk.h', - 'browser/ui/gtk/autofill/autofill_external_delegate_gtk.cc', - 'browser/ui/gtk/autofill/autofill_external_delegate_gtk.h', 'browser/ui/gtk/autofill/autofill_popup_view_gtk.cc', 'browser/ui/gtk/autofill/autofill_popup_view_gtk.h', 'browser/ui/gtk/avatar_menu_bubble_gtk.cc', @@ -1347,8 +1348,6 @@ 'browser/ui/views/ash/tab_scrubber.cc', 'browser/ui/views/autofill/autofill_dialog_views.cc', 'browser/ui/views/autofill/autofill_dialog_views.h', - 'browser/ui/views/autofill/autofill_external_delegate_views.cc', - 'browser/ui/views/autofill/autofill_external_delegate_views.h', 'browser/ui/views/autofill/autofill_popup_view_views.cc', 'browser/ui/views/autofill/autofill_popup_view_views.h', 'browser/ui/views/avatar_menu_bubble_view.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 51a23cd..81ce1d0 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -837,7 +837,7 @@ 'browser/app_controller_mac_browsertest.mm', 'browser/autocomplete/autocomplete_browsertest.cc', 'browser/autofill/autofill_browsertest.cc', - 'browser/autofill/autofill_popup_view_browsertest.cc', + 'browser/autofill/autofill_external_delegate_browsertest.cc', 'browser/autofill/form_structure_browsertest.cc', 'browser/automation/automation_misc_browsertest.cc', 'browser/automation/automation_tab_helper_browsertest.cc', @@ -1166,7 +1166,6 @@ 'browser/ui/find_bar/find_bar_host_browsertest.cc', 'browser/ui/fullscreen/fullscreen_controller_browsertest.cc', 'browser/ui/global_error/global_error_service_browsertest.cc', - 'browser/ui/gtk/autofill/autofill_external_delegate_gtk_browsertest.cc', 'browser/ui/gtk/bubble/bubble_gtk_browsertest.cc', 'browser/ui/gtk/confirm_bubble_gtk_browsertest.cc', 'browser/ui/gtk/location_bar_view_gtk_browsertest.cc', @@ -1182,7 +1181,6 @@ 'browser/ui/startup/startup_browser_creator_browsertest.cc', 'browser/ui/tab_modal_confirm_dialog_browsertest.cc', 'browser/ui/tab_modal_confirm_dialog_browsertest.h', - 'browser/ui/views/autofill/autofill_external_delegate_views_browsertest.cc', 'browser/ui/views/browser_actions_container_browsertest.cc', 'browser/ui/views/find_bar_controller_browsertest.cc', 'browser/ui/views/frame/app_non_client_frame_view_ash_browsertest.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 5a5d16d..561cfa0 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -459,7 +459,6 @@ 'browser/autofill/autofill_merge_unittest.cc', 'browser/autofill/autofill_metrics_unittest.cc', 'browser/autofill/autofill_profile_unittest.cc', - 'browser/autofill/autofill_popup_unittest.cc', 'browser/autofill/autofill_regexes_unittest.cc', 'browser/autofill/autofill_type_unittest.cc', 'browser/autofill/autofill_xml_parser_unittest.cc', @@ -1163,6 +1162,7 @@ 'browser/ui/ash/launcher/chrome_launcher_controller_per_browser_unittest.cc', 'browser/ui/ash/window_positioner_unittest.cc', 'browser/ui/auto_login_prompter_unittest.cc', + 'browser/ui/autofill/autofill_popup_controller_unittest.cc', 'browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc', 'browser/ui/bookmarks/bookmark_prompt_controller_unittest.cc', 'browser/ui/bookmarks/bookmark_ui_utils_unittest.cc', @@ -2130,6 +2130,10 @@ # Test files cannot be opened on Android. 'browser/google_apis/gdata_wapi_operations_unittest.cc', 'browser/google_apis/gdata_wapi_parser_unittest.cc', + + # The autofill popup is implemented in mostly native code on + # Android. + 'browser/ui/autofill/autofill_popup_controller_unittest.cc', ], 'sources/': [ ['exclude', '^browser/captive_portal/'], diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 86cdf09..832de43 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -1162,24 +1162,9 @@ void RenderWidgetHostImpl::ForwardTouchEvent( touch_event_queue_->QueueEvent(touch_event); } -#if defined(TOOLKIT_GTK) -bool RenderWidgetHostImpl::KeyPressListenersHandleEvent(GdkEventKey* event) { - if (event->type != GDK_KEY_PRESS) - return false; - - for (std::list<KeyboardListener*>::iterator it = keyboard_listeners_.begin(); - it != keyboard_listeners_.end(); ++it) { - if ((*it)->HandleKeyPressEvent(event)) - return true; - } - - return false; -} -#endif // defined(TOOLKIT_GTK) - -#if defined(TOOLKIT_VIEWS) -bool RenderWidgetHostImpl::KeyPressListenersHandleEvent(ui::KeyEvent* event) { - if (event->type() != ui::ET_KEY_PRESSED) +bool RenderWidgetHostImpl::KeyPressListenersHandleEvent( + const NativeWebKeyboardEvent& event) { + if (event.type != WebKeyboardEvent::RawKeyDown) return false; for (std::list<KeyboardListener*>::iterator it = keyboard_listeners_.begin(); @@ -1190,7 +1175,6 @@ bool RenderWidgetHostImpl::KeyPressListenersHandleEvent(ui::KeyEvent* event) { return false; } -#endif // defined(TOOLKIT_VIEWS) void RenderWidgetHostImpl::AddKeyboardListener(KeyboardListener* listener) { keyboard_listeners_.push_back(listener); diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 7c335f4..30c8b12 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -249,15 +249,9 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, void ForwardGestureEventImmediately( const WebKit::WebGestureEvent& gesture_event); -#if defined(TOOLKIT_GTK) // Give key press listeners a chance to handle this key press. This allow // widgets that don't have focus to still handle key presses. - bool KeyPressListenersHandleEvent(GdkEventKey* event); -#endif // defined(TOOLKIT_GTK) - -#if defined(TOOLKIT_VIEWS) - bool KeyPressListenersHandleEvent(ui::KeyEvent* event); -#endif // defined(TOOLKIT_VIEWS) + bool KeyPressListenersHandleEvent(const NativeWebKeyboardEvent& event); void CancelUpdateTextDirection(); diff --git a/content/browser/renderer_host/render_widget_host_view_gtk.cc b/content/browser/renderer_host/render_widget_host_view_gtk.cc index 70ab67c..0ecfb35 100644 --- a/content/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/content/browser/renderer_host/render_widget_host_view_gtk.cc @@ -225,7 +225,9 @@ class RenderWidgetHostViewGtkWidget { if (should_close_on_escape && GDK_Escape == event->keyval) { host_view->host_->Shutdown(); } else if (host_view->host_ && - host_view->host_->KeyPressListenersHandleEvent(event)) { + host_view->host_->KeyPressListenersHandleEvent( + NativeWebKeyboardEvent(reinterpret_cast<GdkEvent*>( + event)))) { return TRUE; } else { // Send key event to input method. diff --git a/content/browser/renderer_host/render_widget_host_view_win.cc b/content/browser/renderer_host/render_widget_host_view_win.cc index 2cf0cc7..d8c2855 100644 --- a/content/browser/renderer_host/render_widget_host_view_win.cc +++ b/content/browser/renderer_host/render_widget_host_view_win.cc @@ -1825,12 +1825,13 @@ LRESULT RenderWidgetHostViewWin::OnKeyEvent(UINT message, WPARAM wparam, MSG msg = { m_hWnd, message, wparam, lparam }; ui::KeyEvent key_event(msg, message == WM_CHAR); if (render_widget_host_ && - render_widget_host_->KeyPressListenersHandleEvent(&key_event)) + render_widget_host_->KeyPressListenersHandleEvent( + NativeWebKeyboardEvent(msg))) return 0; - if (render_widget_host_ && !ignore_keyboard_event) { + if (render_widget_host_ && !ignore_keyboard_event) render_widget_host_->ForwardKeyboardEvent(NativeWebKeyboardEvent(msg)); - } + return 0; } diff --git a/content/public/browser/keyboard_listener.h b/content/public/browser/keyboard_listener.h index 0609b4b..e69ab49 100644 --- a/content/public/browser/keyboard_listener.h +++ b/content/public/browser/keyboard_listener.h @@ -7,27 +7,18 @@ #include "content/common/content_export.h" -// All systems should support key listening through ui::KeyEvent. -// GTK doesn't because there is no easy way to convet GdkEventKey to -// ui::KeyEvent and since it is going away soon, it is not worth the effort. -#if defined(TOOLKIT_GTK) -typedef struct _GdkEventKey GdkEventKey; -#else -namespace ui { -class KeyEvent; -} // namespace ui -#endif +namespace content { + +struct NativeWebKeyboardEvent; class CONTENT_EXPORT KeyboardListener { public: -#if defined(TOOLKIT_GTK) - virtual bool HandleKeyPressEvent(GdkEventKey* event) = 0; -#else - virtual bool HandleKeyPressEvent(ui::KeyEvent* event) = 0; -#endif + virtual bool HandleKeyPressEvent(const NativeWebKeyboardEvent& event) = 0; protected: virtual ~KeyboardListener() {} }; +} // content + #endif // CONTENT_PUBLIC_BROWSER_KEYBOARD_LISTENER_H_ |