diff options
author | dbeam@chromium.org <dbeam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-12 07:53:29 +0000 |
---|---|---|
committer | dbeam@chromium.org <dbeam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-12 07:53:29 +0000 |
commit | 71b6272a6adf06fcd70f402cb8bfd83aa986449e (patch) | |
tree | 6097460ef7c4afb8f6f930fc0eb51a05bface6ef | |
parent | 1c881566bfc202570c21eca4902c69711d8219f1 (diff) | |
download | chromium_src-71b6272a6adf06fcd70f402cb8bfd83aa986449e.zip chromium_src-71b6272a6adf06fcd70f402cb8bfd83aa986449e.tar.gz chromium_src-71b6272a6adf06fcd70f402cb8bfd83aa986449e.tar.bz2 |
Hide validation bubble when Autofill popup shows (so they're not both showing
simultaneously).
BUG=306197
R=estade@chromium.org,groby@chromium.org
Review URL: https://codereview.chromium.org/26901005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@228338 0039d316-1c4b-4281-b951-d872f2087c98
15 files changed, 104 insertions, 17 deletions
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc index fb8a53d..2fbc3d7 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc +++ b/chrome/browser/ui/autofill/autofill_dialog_controller_browsertest.cc @@ -559,6 +559,30 @@ IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, } } +IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, ShouldShowErrorBubble) { + EXPECT_TRUE(controller()->ShouldShowErrorBubble()); + + CreditCard card(test::GetCreditCard()); + ASSERT_FALSE(card.IsVerified()); + controller()->GetTestingManager()->AddTestingCreditCard(&card); + + const DetailInputs& cc_inputs = + controller()->RequestedFieldsForSection(SECTION_CC); + const DetailInput& cc_number_input = cc_inputs[0]; + ASSERT_EQ(CREDIT_CARD_NUMBER, cc_number_input.type); + + TestableAutofillDialogView* view = controller()->GetTestableView(); + view->SetTextContentsOfInput( + cc_number_input, + card.GetRawInfo(CREDIT_CARD_NUMBER).substr(0, 1)); + + view->ActivateInput(cc_number_input); + EXPECT_FALSE(controller()->ShouldShowErrorBubble()); + + controller()->FocusMoved(); + EXPECT_TRUE(controller()->ShouldShowErrorBubble()); +} + // Tests that credit card number is disabled while editing a Wallet instrument. IN_PROC_BROWSER_TEST_F(AutofillDialogControllerTest, WalletCreditCardDisabled) { std::vector<std::string> usernames; diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc index 5ea39f9..90a99ae 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc @@ -1897,17 +1897,24 @@ void AutofillDialogControllerImpl::UserEditedOrActivatedInput( base::i18n::IsRTL() ? base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT); popup_controller_->set_hide_on_outside_click(true); + + // |input_showing_popup_| must be set before calling |Show()|. + input_showing_popup_ = input; + popup_controller_->Show(popup_values, popup_labels, popup_icons, popup_ids); - input_showing_popup_ = input; } void AutofillDialogControllerImpl::FocusMoved() { HidePopup(); } +bool AutofillDialogControllerImpl::ShouldShowErrorBubble() const { + return !input_showing_popup_; +} + void AutofillDialogControllerImpl::ViewClosed() { GetManager()->RemoveObserver(this); @@ -2078,6 +2085,9 @@ content::WebContents* AutofillDialogControllerImpl::GetWebContents() { void AutofillDialogControllerImpl::OnPopupShown( content::RenderWidgetHost::KeyPressEventCallback* callback) { + ScopedViewUpdates update(view_.get()); + view_->UpdateErrorBubble(); + GetMetricLogger().LogDialogPopupEvent(AutofillMetrics::DIALOG_POPUP_SHOWN); } diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h index d752901..ad057f4 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h +++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h @@ -153,6 +153,7 @@ class AutofillDialogControllerImpl : public AutofillDialogViewDelegate, virtual bool HandleKeyPressEventInInput( const content::NativeWebKeyboardEvent& event) OVERRIDE; virtual void FocusMoved() OVERRIDE; + virtual bool ShouldShowErrorBubble() const OVERRIDE; virtual void ViewClosed() OVERRIDE; virtual std::vector<DialogNotification> CurrentNotifications() OVERRIDE; virtual void LinkClicked(const GURL& url) OVERRIDE; diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc index debb347..799d7a2 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc @@ -180,6 +180,10 @@ class TestAutofillDialogView : public AutofillDialogView { EXPECT_GE(updates_started_, 1); } + virtual void UpdateErrorBubble() OVERRIDE { + EXPECT_GE(updates_started_, 1); + } + virtual void FillSection(DialogSection section, const DetailInput& originating_input) OVERRIDE {}; virtual void GetUserInput(DialogSection section, DetailOutputMap* output) diff --git a/chrome/browser/ui/autofill/autofill_dialog_view.h b/chrome/browser/ui/autofill/autofill_dialog_view.h index b1012d6..aa27201 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_view.h +++ b/chrome/browser/ui/autofill/autofill_dialog_view.h @@ -65,6 +65,9 @@ class AutofillDialogView { // Called when the contents of a section have changed. virtual void UpdateSection(DialogSection section) = 0; + // Updates the error bubble for this view. + virtual void UpdateErrorBubble() = 0; + // Fills the given section with Autofill data that was triggered by a user // interaction with |originating_input|. virtual void FillSection(DialogSection section, diff --git a/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h b/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h index 3bfe14e..bcb33c6 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h +++ b/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h @@ -167,6 +167,9 @@ class AutofillDialogViewDelegate { // Called when focus has changed position within the view. virtual void FocusMoved() = 0; + // Whether the view should show a validation error bubble. + virtual bool ShouldShowErrorBubble() const = 0; + // Miscellany ---------------------------------------------------------------- // Called when the view has been closed. diff --git a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h index 34c662ebe..99ccfc5 100644 --- a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h +++ b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h @@ -69,6 +69,7 @@ class MockAutofillDialogViewDelegate : public AutofillDialogViewDelegate { MOCK_METHOD1(HandleKeyPressEventInInput, bool(const content::NativeWebKeyboardEvent& event)); MOCK_METHOD0(FocusMoved, void()); + MOCK_CONST_METHOD0(ShouldShowErrorBubble, bool()); MOCK_METHOD0(ViewClosed, void()); MOCK_METHOD0(CurrentNotifications,std::vector<DialogNotification>()); MOCK_METHOD1(LinkClicked, void(const GURL&)); diff --git a/chrome/browser/ui/cocoa/autofill/autofill_details_container.h b/chrome/browser/ui/cocoa/autofill/autofill_details_container.h index 9c90833..2cd82cd 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_details_container.h +++ b/chrome/browser/ui/cocoa/autofill/autofill_details_container.h @@ -31,7 +31,7 @@ class AutofillDialogViewDelegate; base::scoped_nsobject<NSMutableArray> details_; // An info bubble to display validation errors. - base::scoped_nsobject<InfoBubbleView> infoBubble_; + base::scoped_nsobject<InfoBubbleView> errorBubble_; autofill::AutofillDialogViewDelegate* delegate_; // Not owned. } @@ -42,6 +42,9 @@ class AutofillDialogViewDelegate; // Retrieve the container for the specified |section|. - (AutofillSectionContainer*)sectionForId:(autofill::DialogSection)section; +// Called when |errorBubble_| needs to be updated. +- (void)updateErrorBubble; + // Called when the delegate-maintained suggestions model has changed. - (void)modelChanged; diff --git a/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm index 6996225..3adf3ce 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm +++ b/chrome/browser/ui/cocoa/autofill/autofill_details_container.mm @@ -61,21 +61,21 @@ SkColor const kWarningColor = 0xffde4932; // SkColorSetRGB(0xde, 0x49, 0x32); for (AutofillSectionContainer* container in details_.get()) [[scrollView_ documentView] addSubview:[container view]]; - infoBubble_.reset([[InfoBubbleView alloc] initWithFrame:NSZeroRect]); - [infoBubble_ setBackgroundColor: + errorBubble_.reset([[InfoBubbleView alloc] initWithFrame:NSZeroRect]); + [errorBubble_ setBackgroundColor: gfx::SkColorToCalibratedNSColor(kWarningColor)]; - [infoBubble_ setArrowLocation:info_bubble::kTopCenter]; - [infoBubble_ setAlignment:info_bubble::kAlignArrowToAnchor]; - [infoBubble_ setHidden:YES]; + [errorBubble_ setArrowLocation:info_bubble::kTopCenter]; + [errorBubble_ setAlignment:info_bubble::kAlignArrowToAnchor]; + [errorBubble_ setHidden:YES]; base::scoped_nsobject<NSTextField> label([[NSTextField alloc] init]); [label setEditable:NO]; [label setBordered:NO]; [label setDrawsBackground:NO]; [label setTextColor:[NSColor whiteColor]]; - [infoBubble_ addSubview:label]; + [errorBubble_ addSubview:label]; - [[scrollView_ documentView] addSubview:infoBubble_]; + [[scrollView_ documentView] addSubview:errorBubble_]; [self performLayout]; } @@ -126,16 +126,22 @@ SkColor const kWarningColor = 0xffde4932; // SkColorSetRGB(0xde, 0x49, 0x32); return allValid; } +- (void)updateErrorBubble { + if (!delegate_->ShouldShowErrorBubble()) + [errorBubble_ setHidden:YES]; +} + // TODO(groby): Unify with BaseBubbleController's originFromAnchor:view:. - (NSPoint)originFromAnchorView:(NSView*)view { // All math done in window coordinates, since views might be flipped. NSRect viewRect = [view convertRect:[view bounds] toView:nil]; NSPoint anchorPoint = NSMakePoint(NSMidX(viewRect), NSMinY(viewRect)); - NSRect bubbleRect = [infoBubble_ convertRect:[infoBubble_ bounds] toView:nil]; + NSRect bubbleRect = [errorBubble_ convertRect:[errorBubble_ bounds] + toView:nil]; NSPoint bubbleOrigin = NSMakePoint(anchorPoint.x - NSWidth(bubbleRect) / 2.0, anchorPoint.y - NSHeight(bubbleRect)); - return [[infoBubble_ superview] convertPoint:bubbleOrigin fromView:nil]; + return [[errorBubble_ superview] convertPoint:bubbleOrigin fromView:nil]; } - (void)updateMessageForField:(NSControl<AutofillInputField>*)field { @@ -144,25 +150,29 @@ SkColor const kWarningColor = 0xffde4932; // SkColorSetRGB(0xde, 0x49, 0x32); // firstResponder is a subview of the NSTextField, not the field itself. NSView* firstResponderView = base::mac::ObjCCast<NSView>([[field window] firstResponder]); - if (![firstResponderView isDescendantOf:field]) { + if (![firstResponderView isDescendantOf:field]) + return; + + if (!delegate_->ShouldShowErrorBubble()) { + DCHECK([errorBubble_ isHidden]); return; } if ([field invalid]) { const CGFloat labelInset = 3.0; - NSTextField* label = [[infoBubble_ subviews] objectAtIndex:0]; + NSTextField* label = [[errorBubble_ subviews] objectAtIndex:0]; [label setStringValue:[field validityMessage]]; [label sizeToFit]; NSSize bubbleSize = [label frame].size; bubbleSize.width += 2 * labelInset; bubbleSize.height += 2 * labelInset + info_bubble::kBubbleArrowHeight; - [infoBubble_ setFrameSize:bubbleSize]; + [errorBubble_ setFrameSize:bubbleSize]; [label setFrameOrigin:NSMakePoint(labelInset, labelInset)]; - [infoBubble_ setFrameOrigin:[self originFromAnchorView:field]]; - [infoBubble_ setHidden:NO]; + [errorBubble_ setFrameOrigin:[self originFromAnchorView:field]]; + [errorBubble_ setHidden:NO]; } else { - [infoBubble_ setHidden:YES]; + [errorBubble_ setHidden:YES]; } } diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h index 601a40b..4cded2c 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h +++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h @@ -50,6 +50,7 @@ class AutofillDialogCocoa : public AutofillDialogView, virtual void UpdateForErrors() OVERRIDE; virtual void UpdateNotificationArea() OVERRIDE; virtual void UpdateSection(DialogSection section) OVERRIDE; + virtual void UpdateErrorBubble() OVERRIDE; virtual void FillSection(DialogSection section, const DetailInput& originating_input) OVERRIDE; virtual void GetUserInput(DialogSection section, @@ -149,6 +150,7 @@ class AutofillDialogCocoa : public AutofillDialogView, - (content::NavigationController*)showSignIn; - (void)hideSignIn; - (void)modelChanged; +- (void)updateErrorBubble; @end diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm index 4d8541aa..640f46d 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm +++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm @@ -149,6 +149,10 @@ void AutofillDialogCocoa::ModelChanged() { [sheet_delegate_ modelChanged]; } +void AutofillDialogCocoa::UpdateErrorBubble() { + [sheet_delegate_ updateErrorBubble]; +} + TestableAutofillDialogView* AutofillDialogCocoa::GetTestableView() { return this; } @@ -546,6 +550,10 @@ void AutofillDialogCocoa::OnConstrainedWindowClosed( [mainContainer_ modelChanged]; } +- (void)updateErrorBubble { + [mainContainer_ updateErrorBubble]; +} + @end diff --git a/chrome/browser/ui/cocoa/autofill/autofill_main_container.h b/chrome/browser/ui/cocoa/autofill/autofill_main_container.h index 559f548..b2e72c7 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_main_container.h +++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container.h @@ -68,6 +68,9 @@ namespace autofill { // Called when there are changes to the notification area. - (void)updateNotificationArea; +// Called when the error bubble needs to be updated. +- (void)updateErrorBubble; + // Validates form input data. - (BOOL)validate; diff --git a/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm index 452270c..76a3b47 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm +++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm @@ -289,6 +289,10 @@ (delegate_->ShouldSaveInChrome() ? NSOnState : NSOffState)]; } +- (void)updateErrorBubble { + [detailsContainer_ updateErrorBubble]; +} + @end diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc index 64c2235..3fba317 100644 --- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc +++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc @@ -1421,6 +1421,11 @@ void AutofillDialogViews::UpdateSection(DialogSection section) { UpdateSectionImpl(section, true); } +void AutofillDialogViews::UpdateErrorBubble() { + if (!delegate_->ShouldShowErrorBubble()) + HideErrorBubble(); +} + void AutofillDialogViews::FillSection(DialogSection section, const DetailInput& originating_input) { DetailsGroup* group = GroupForSection(section); @@ -2166,6 +2171,11 @@ void AutofillDialogViews::ShowErrorBubbleForViewIfNecessary(views::View* view) { if (!view->GetWidget()) return; + if (!delegate_->ShouldShowErrorBubble()) { + DCHECK(!error_bubble_); + return; + } + std::map<views::View*, base::string16>::iterator error_message = validity_map_.find(view); if (error_message != validity_map_.end()) { diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.h b/chrome/browser/ui/views/autofill/autofill_dialog_views.h index 4e64fea..ef59102 100644 --- a/chrome/browser/ui/views/autofill/autofill_dialog_views.h +++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.h @@ -85,6 +85,7 @@ class AutofillDialogViews : public AutofillDialogView, virtual void UpdateForErrors() OVERRIDE; virtual void UpdateNotificationArea() OVERRIDE; virtual void UpdateSection(DialogSection section) OVERRIDE; + virtual void UpdateErrorBubble() OVERRIDE; virtual void FillSection(DialogSection section, const DetailInput& originating_input) OVERRIDE; virtual void GetUserInput(DialogSection section, |