Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(334)

Side by Side Diff: chrome/browser/ui/cocoa/autofill/autofill_details_container.mm

Issue 49063012: [rAC, OSX] Use bubble windows for error messages. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix failing tests. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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];
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698