Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/ui/cocoa/autofill/autofill_details_container.h" | 5 #import "chrome/browser/ui/cocoa/autofill/autofill_details_container.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/mac/foundation_util.h" | 9 #include "base/mac/foundation_util.h" |
| 10 #include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h" | 10 #include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h" |
| 11 #import "chrome/browser/ui/cocoa/autofill/autofill_error_bubble_controller.h" | |
| 11 #import "chrome/browser/ui/cocoa/autofill/autofill_section_container.h" | 12 #import "chrome/browser/ui/cocoa/autofill/autofill_section_container.h" |
| 12 #import "chrome/browser/ui/cocoa/info_bubble_view.h" | |
| 13 #include "skia/ext/skia_utils_mac.h" | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 // Imported constant from Views version. TODO(groby): Share. | |
| 18 SkColor const kWarningColor = 0xffde4932; // SkColorSetRGB(0xde, 0x49, 0x32); | |
| 19 | |
| 20 } // namespace | |
| 21 | |
| 22 @interface AutofillDetailsContainer () | |
| 23 // Compute infobubble origin based on anchor/view. | |
| 24 - (NSPoint)originFromAnchorView:(NSView*)view; | |
| 25 @end | |
| 26 | 13 |
| 27 @implementation AutofillDetailsContainer | 14 @implementation AutofillDetailsContainer |
| 28 | 15 |
| 29 - (id)initWithDelegate:(autofill::AutofillDialogViewDelegate*)delegate { | 16 - (id)initWithDelegate:(autofill::AutofillDialogViewDelegate*)delegate { |
| 30 if (self = [super init]) { | 17 if (self = [super init]) { |
| 31 delegate_ = delegate; | 18 delegate_ = delegate; |
| 32 } | 19 } |
| 33 return self; | 20 return self; |
| 34 } | 21 } |
| 35 | 22 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 54 [scrollView_ setHasHorizontalScroller:NO]; | 41 [scrollView_ setHasHorizontalScroller:NO]; |
| 55 [scrollView_ setBorderType:NSNoBorder]; | 42 [scrollView_ setBorderType:NSNoBorder]; |
| 56 [scrollView_ setAutohidesScrollers:YES]; | 43 [scrollView_ setAutohidesScrollers:YES]; |
| 57 [self setView:scrollView_]; | 44 [self setView:scrollView_]; |
| 58 | 45 |
| 59 [scrollView_ setDocumentView:[[NSView alloc] initWithFrame:NSZeroRect]]; | 46 [scrollView_ setDocumentView:[[NSView alloc] initWithFrame:NSZeroRect]]; |
| 60 | 47 |
| 61 for (AutofillSectionContainer* container in details_.get()) | 48 for (AutofillSectionContainer* container in details_.get()) |
| 62 [[scrollView_ documentView] addSubview:[container view]]; | 49 [[scrollView_ documentView] addSubview:[container view]]; |
| 63 | 50 |
| 64 errorBubble_.reset([[InfoBubbleView alloc] initWithFrame:NSZeroRect]); | |
| 65 [errorBubble_ setBackgroundColor: | |
| 66 gfx::SkColorToCalibratedNSColor(kWarningColor)]; | |
| 67 [errorBubble_ setArrowLocation:info_bubble::kTopCenter]; | |
| 68 [errorBubble_ setAlignment:info_bubble::kAlignArrowToAnchor]; | |
| 69 [errorBubble_ setHidden:YES]; | |
| 70 | |
| 71 base::scoped_nsobject<NSTextField> label([[NSTextField alloc] init]); | |
| 72 [label setEditable:NO]; | |
| 73 [label setBordered:NO]; | |
| 74 [label setDrawsBackground:NO]; | |
| 75 [label setTextColor:[NSColor whiteColor]]; | |
| 76 [errorBubble_ addSubview:label]; | |
| 77 | |
| 78 [[scrollView_ documentView] addSubview:errorBubble_]; | |
| 79 | |
| 80 [self performLayout]; | 51 [self performLayout]; |
| 81 } | 52 } |
| 82 | 53 |
| 83 - (NSSize)preferredSize { | 54 - (NSSize)preferredSize { |
| 84 NSSize size = NSZeroSize; | 55 NSSize size = NSZeroSize; |
| 85 for (AutofillSectionContainer* container in details_.get()) { | 56 for (AutofillSectionContainer* container in details_.get()) { |
| 86 NSSize containerSize = [container preferredSize]; | 57 NSSize containerSize = [container preferredSize]; |
| 87 size.height += containerSize.height; | 58 size.height += containerSize.height; |
| 88 size.width = std::max(containerSize.width, size.width); | 59 size.width = std::max(containerSize.width, size.width); |
| 89 } | 60 } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 120 - (BOOL)validate { | 91 - (BOOL)validate { |
| 121 bool allValid = true; | 92 bool allValid = true; |
| 122 for (AutofillSectionContainer* details in details_.get()) { | 93 for (AutofillSectionContainer* details in details_.get()) { |
| 123 if (![[details view] isHidden]) | 94 if (![[details view] isHidden]) |
| 124 allValid = [details validateFor:autofill::VALIDATE_FINAL] && allValid; | 95 allValid = [details validateFor:autofill::VALIDATE_FINAL] && allValid; |
| 125 } | 96 } |
| 126 return allValid; | 97 return allValid; |
| 127 } | 98 } |
| 128 | 99 |
| 129 - (void)updateErrorBubble { | 100 - (void)updateErrorBubble { |
| 130 if (!delegate_->ShouldShowErrorBubble()) | 101 if (!delegate_->ShouldShowErrorBubble()) { |
| 131 [errorBubble_ setHidden:YES]; | 102 [errorBubbleController_ close]; |
| 103 } | |
| 132 } | 104 } |
| 133 | 105 |
| 134 // TODO(groby): Unify with BaseBubbleController's originFromAnchor:view:. | 106 - (NSPoint)anchorPointFromView:(NSView*)view { |
| 135 - (NSPoint)originFromAnchorView:(NSView*)view { | |
| 136 // All math done in window coordinates, since views might be flipped. | 107 // All math done in window coordinates, since views might be flipped. |
| 137 NSRect viewRect = [view convertRect:[view bounds] toView:nil]; | 108 NSRect viewRect = [view convertRect:[view bounds] toView:nil]; |
| 138 NSPoint anchorPoint = | 109 NSPoint anchorPoint = |
| 139 NSMakePoint(NSMidX(viewRect), NSMinY(viewRect)); | 110 NSMakePoint(NSMidX(viewRect), NSMinY(viewRect)); |
| 140 NSRect bubbleRect = [errorBubble_ convertRect:[errorBubble_ bounds] | 111 return [[view window] convertBaseToScreen:anchorPoint]; |
| 141 toView:nil]; | 112 } |
| 142 NSPoint bubbleOrigin = NSMakePoint(anchorPoint.x - NSWidth(bubbleRect) / 2.0, | 113 |
| 143 anchorPoint.y - NSHeight(bubbleRect)); | 114 - (void)errorBubbleWindowWillClose:(NSNotification*)notification { |
| 144 return [[errorBubble_ superview] convertPoint:bubbleOrigin fromView:nil]; | 115 DCHECK_EQ([notification object], [errorBubbleController_ window]); |
| 116 | |
| 117 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |
| 118 [center removeObserver:self | |
| 119 name:NSWindowWillCloseNotification | |
| 120 object:[errorBubbleController_ window]]; | |
| 121 errorBubbleController_ = nil; | |
| 122 } | |
| 123 | |
| 124 - (void)showErrorBubbleForField:(NSControl<AutofillInputField>*)field { | |
| 125 DCHECK(!errorBubbleController_); | |
| 126 NSWindow* parentWindow = [field window]; | |
| 127 DCHECK(parentWindow); | |
| 128 errorBubbleController_ = | |
| 129 [[AutofillErrorBubbleController alloc] | |
| 130 initWithParentWindow:parentWindow | |
| 131 message:[field validityMessage]]; | |
| 132 | |
| 133 // Handle bubble self-deleting. | |
| 134 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |
|
Robert Sesek
2013/11/04 23:49:18
Is it possible for the bubble to close itself ever
groby-ooo-7-16
2013/11/05 00:51:48
Yes, it can, when the parent window resigns key st
| |
| 135 [center addObserver:self | |
| 136 selector:@selector(errorBubbleWindowWillClose:) | |
| 137 name:NSWindowWillCloseNotification | |
| 138 object:[errorBubbleController_ window]]; | |
| 139 | |
| 140 // Compute anchor point (in window coords - views might be flipped). | |
| 141 NSRect viewRect = [field convertRect:[field bounds] toView:nil]; | |
| 142 NSPoint anchorPoint = NSMakePoint(NSMidX(viewRect), NSMinY(viewRect)); | |
| 143 [errorBubbleController_ setAnchorPoint: | |
| 144 [parentWindow convertBaseToScreen:anchorPoint]]; | |
| 145 | |
| 146 [errorBubbleController_ showWindow:self]; | |
| 145 } | 147 } |
| 146 | 148 |
| 147 - (void)updateMessageForField:(NSControl<AutofillInputField>*)field { | 149 - (void)updateMessageForField:(NSControl<AutofillInputField>*)field { |
| 148 // Ignore fields that are not first responder. Testing this is a bit | 150 // Ignore fields that are not first responder. Testing this is a bit |
| 149 // convoluted, since for NSTextFields with firstResponder status, the | 151 // convoluted, since for NSTextFields with firstResponder status, the |
| 150 // firstResponder is a subview of the NSTextField, not the field itself. | 152 // firstResponder is a subview of the NSTextField, not the field itself. |
| 151 NSView* firstResponderView = | 153 NSView* firstResponderView = |
| 152 base::mac::ObjCCast<NSView>([[field window] firstResponder]); | 154 base::mac::ObjCCast<NSView>([[field window] firstResponder]); |
| 153 if (![firstResponderView isDescendantOf:field]) | 155 if (![firstResponderView isDescendantOf:field]) |
| 154 return; | 156 return; |
| 155 | |
| 156 if (!delegate_->ShouldShowErrorBubble()) { | 157 if (!delegate_->ShouldShowErrorBubble()) { |
| 157 DCHECK([errorBubble_ isHidden]); | 158 DCHECK(!errorBubbleController_); |
| 158 return; | 159 return; |
| 159 } | 160 } |
| 160 | 161 |
| 161 if ([field invalid]) { | 162 if ([field invalid]) { |
| 162 const CGFloat labelInset = 3.0; | 163 [self showErrorBubbleForField:field]; |
| 163 | |
| 164 NSTextField* label = [[errorBubble_ subviews] objectAtIndex:0]; | |
| 165 [label setStringValue:[field validityMessage]]; | |
| 166 [label sizeToFit]; | |
| 167 NSSize bubbleSize = [label frame].size; | |
| 168 bubbleSize.width += 2 * labelInset; | |
| 169 bubbleSize.height += 2 * labelInset + info_bubble::kBubbleArrowHeight; | |
| 170 [errorBubble_ setFrameSize:bubbleSize]; | |
| 171 [label setFrameOrigin:NSMakePoint(labelInset, labelInset)]; | |
| 172 [errorBubble_ setFrameOrigin:[self originFromAnchorView:field]]; | |
| 173 [errorBubble_ setHidden:NO]; | |
| 174 } else { | 164 } else { |
| 175 [errorBubble_ setHidden:YES]; | 165 [errorBubbleController_ close]; |
| 176 } | 166 } |
| 177 } | 167 } |
| 178 | 168 |
| 179 @end | 169 @end |
| OLD | NEW |