OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #import "chrome/browser/ui/cocoa/permission_bubble_controller.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/mac/mac_util.h" | |
10 #include "base/strings/sys_string_conversions.h" | |
11 #include "base/strings/utf_string_conversions.h" | |
groby-ooo-7-16
2014/01/31 22:31:51
I don't think you're using these
leng
2014/02/03 22:38:04
Only the sys_strings one.
Done.
| |
12 #include "chrome/browser/ui/browser.h" | |
13 #include "chrome/browser/ui/browser_finder.h" | |
14 #import "chrome/browser/ui/chrome_style.h" | |
15 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | |
16 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h" | |
17 #import "chrome/browser/ui/cocoa/info_bubble_view.h" | |
18 #import "chrome/browser/ui/cocoa/info_bubble_window.h" | |
19 #include "chrome/browser/ui/cocoa/permission_bubble_cocoa.h" | |
20 #include "chrome/browser/ui/website_settings/permission_bubble_delegate.h" | |
21 #include "chrome/browser/ui/website_settings/permission_bubble_view.h" | |
22 #include "content/public/browser/user_metrics.h" | |
23 #include "grit/generated_resources.h" | |
24 #include "skia/ext/skia_utils_mac.h" | |
25 #include "ui/base/l10n/l10n_util_mac.h" | |
26 | |
27 using base::UserMetricsAction; | |
28 | |
29 namespace { | |
30 const CGFloat kHorizontalPadding = 20.0f; | |
31 const CGFloat kVerticalPadding = 20.0f; | |
32 const CGFloat kCheckboxYAdjustment = 2; | |
33 | |
34 const CGFloat kButtonWidth = 80.0f; | |
35 const CGFloat kButtonHeight = 30.0f; | |
36 | |
37 const base::char16 kBulletPoint = 0x2022; | |
38 const int kButtonBackgroundColor = 239; | |
groby-ooo-7-16
2014/01/31 22:31:51
Is that shared across platforms? Would it be worth
leng
2014/02/03 22:38:04
I don't know. I took the color from the mocks, so
groby-ooo-7-16
2014/02/04 02:39:29
"theme" file is fancy speak for a shared header wi
leng
2014/02/04 21:48:22
I see. Thanks. :)
This is no longer relevant, th
| |
39 | |
40 } // namespace | |
41 | |
42 @interface PermissionBubbleController (PrivateAPI) | |
groby-ooo-7-16
2014/01/31 22:31:51
just
@interface PermissionBubbleController ()
leng
2014/02/03 22:38:04
Done.
| |
43 | |
44 // Called when the 'ok' button is pressed. | |
45 - (void)ok; | |
groby-ooo-7-16
2014/01/31 22:31:51
NSButton actions always take a sender parameter, i
leng
2014/02/03 22:38:04
Done.
| |
46 | |
47 // Called when the 'allow' button is pressed. | |
48 - (void)allow; | |
groby-ooo-7-16
2014/01/31 22:31:51
nit: Button callbacks except ok/cancel are usually
leng
2014/02/03 22:38:04
Done.
| |
49 | |
50 // Called when the 'block' button is pressed. | |
51 - (void)block; | |
52 | |
53 // Called when the 'customize' button is pressed. | |
54 - (void)customize; | |
55 | |
56 // Called when a checkbox changes from checked to unchecked, or vice versa. | |
57 - (void)checkboxChanged; | |
58 | |
59 @end | |
60 | |
61 @implementation PermissionBubbleController | |
62 | |
63 - (id)initWithParentWindow:(NSWindow*)parentWindow | |
64 bridge:(PermissionBubbleCocoa*)bridge { | |
65 DCHECK(parentWindow); | |
66 DCHECK(bridge); | |
67 base::scoped_nsobject<InfoBubbleWindow> window( | |
68 [[InfoBubbleWindow alloc] initWithContentRect:NSMakeRect(0, 0, 240, 150) | |
69 styleMask:NSBorderlessWindowMask | |
70 backing:NSBackingStoreBuffered | |
71 defer:NO]); | |
72 [window setAllowedAnimations:info_bubble::kAnimateNone]; | |
73 if ((self = [super initWithWindow:window | |
74 parentWindow:parentWindow | |
75 anchoredAt:NSZeroPoint])) { | |
76 [self setShouldCloseOnResignKey:NO]; | |
77 [[self bubble] setArrowLocation:info_bubble::kTopLeft]; | |
78 bridge_ = bridge; | |
79 } | |
80 return self; | |
81 } | |
82 | |
83 - (void)windowWillClose:(NSNotification*)notification { | |
84 bridge_->OnBubbleClosing(); | |
85 [super windowWillClose:notification]; | |
86 } | |
87 | |
88 - (void)showAtAnchor:(NSPoint)anchorPoint | |
89 withDelegate:(PermissionBubbleView::Delegate*)delegate | |
90 forRequests:(const std::vector<PermissionBubbleDelegate*>&)requests | |
91 acceptStates:(const std::vector<bool>&)acceptStates | |
92 customizationMode:(BOOL)customizationMode { | |
93 DCHECK(!customizationMode || (requests.size() == acceptStates.size())); | |
94 delegate_ = delegate; | |
95 | |
96 base::scoped_nsobject<NSMutableArray> subViews([[NSMutableArray alloc] init]); | |
groby-ooo-7-16
2014/01/31 22:31:51
Curious: Why a separate NSMutableArray, instead of
leng
2014/02/03 22:38:04
I was copying the behavior from another class. Si
| |
97 BOOL singlePermission = requests.size() == 1; | |
98 NSRect windowFrame = [[self window] frame]; | |
99 CGFloat yOffset = 2 * kVerticalPadding + kButtonHeight; | |
100 CGFloat maxContentsWidth = 0.0f; | |
101 | |
102 for (auto it = requests.begin(); it != requests.end(); it++) { | |
103 base::scoped_nsobject<NSView> permissionView; | |
104 if (customizationMode) { | |
105 int index = it - requests.begin(); | |
106 permissionView.reset( | |
107 [[self checkboxForRequest:(*it) | |
108 checked:acceptStates[index] ? YES : NO] retain]); | |
109 checkboxes_.push_back(permissionView); | |
110 } else { | |
111 permissionView.reset([[self labelForRequest:(*it) | |
112 isSingleRequest:singlePermission] retain]); | |
113 } | |
114 NSPoint origin = [permissionView frame].origin; | |
115 origin.x += kHorizontalPadding; | |
116 origin.y += yOffset; | |
117 [permissionView setFrameOrigin:origin]; | |
118 [subViews addObject:permissionView]; | |
119 | |
120 yOffset += [permissionView frame].size.height; | |
groby-ooo-7-16
2014/01/31 22:31:51
NSHeight([permissionView frame])
leng
2014/02/03 22:38:04
Done.
| |
121 maxContentsWidth = fmax(maxContentsWidth, | |
groby-ooo-7-16
2014/01/31 22:31:51
Please use std::max
Alternatively, you can simply
leng
2014/02/03 22:38:04
I like it - thanks!
Done.
| |
122 [permissionView frame].size.width); | |
123 } | |
124 | |
125 if (!singlePermission && !customizationMode) { | |
126 base::scoped_nsobject<NSView> customizeButton( | |
127 [[self customizationButton] retain]); | |
128 // The Y center should match the Y centers of the buttons. | |
129 CGFloat customizeButtonYOffset = kVerticalPadding + | |
130 (kButtonHeight - [customizeButton frame].size.height) * 0.5f; | |
groby-ooo-7-16
2014/01/31 22:31:51
You might want to ceil/floor this so the button is
leng
2014/02/03 22:38:04
Done.
| |
131 [customizeButton setFrameOrigin:NSMakePoint(kHorizontalPadding, | |
132 customizeButtonYOffset)]; | |
133 [subViews addObject:customizeButton]; | |
134 } | |
135 | |
136 CGFloat windowWidth = fmax(windowFrame.size.width, | |
groby-ooo-7-16
2014/01/31 22:31:51
NSWidth(windowFrame) - we like to pretend we don't
leng
2014/02/03 22:38:04
I didn't know that the structure of NSRect was so
| |
137 maxContentsWidth + 2 * kHorizontalPadding); | |
138 base::scoped_nsobject<NSView> allowOrOkButton; | |
139 if (customizationMode) { | |
140 allowOrOkButton.reset([[self buttonWithTitle:@"OK" | |
141 action:@selector(ok)] retain]); | |
142 } else { | |
143 allowOrOkButton.reset([[self buttonWithTitle:@"Allow" | |
144 action:@selector(allow)] retain]); | |
145 } | |
146 CGFloat xOrigin = windowWidth - kButtonWidth - kHorizontalPadding; | |
147 [allowOrOkButton setFrameOrigin:NSMakePoint(xOrigin, kVerticalPadding)]; | |
148 [subViews addObject:allowOrOkButton]; | |
149 | |
150 if (!customizationMode) { | |
151 base::scoped_nsobject<NSView> blockButton( | |
152 [[self buttonWithTitle:@"Block" action:@selector(block)] retain]); | |
153 xOrigin = NSMinX([allowOrOkButton frame]) - [blockButton frame].size.width - | |
154 kHorizontalPadding * 0.5f; | |
groby-ooo-7-16
2014/01/31 22:31:51
I assume kHorizontalPadding/2 is the gap you want
leng
2014/02/03 22:38:04
Done.
| |
155 [blockButton setFrameOrigin:NSMakePoint(xOrigin, kVerticalPadding)]; | |
156 [subViews addObject:blockButton]; | |
157 } | |
158 | |
159 if (!singlePermission) { | |
160 base::scoped_nsobject<NSView> titleView( | |
161 [[self titleForMultipleRequests] retain]); | |
162 [subViews addObject:titleView]; | |
163 [titleView setFrameOrigin:NSMakePoint(kHorizontalPadding, | |
164 kVerticalPadding + yOffset)]; | |
165 yOffset += [titleView frame].size.height + kVerticalPadding; | |
166 } | |
167 | |
168 [[[self window] contentView] setSubviews:subViews]; | |
169 windowFrame.size.width = windowWidth; | |
170 windowFrame.size.height = yOffset + kVerticalPadding; | |
groby-ooo-7-16
2014/01/31 22:31:51
Please use -frameRectForContentRect to convert the
leng
2014/02/03 22:38:04
Good catch. I've changed the name of the variable
| |
171 [[self window] setFrame:windowFrame display:NO]; | |
172 | |
173 [self setAnchorPoint:anchorPoint]; | |
174 [self showWindow:nil]; | |
175 } | |
176 | |
177 - (NSView*)labelForRequest:(PermissionBubbleDelegate*)request | |
178 isSingleRequest:(BOOL)singleRequest { | |
179 DCHECK(request); | |
180 base::scoped_nsobject<NSTextField> permissionLabel( | |
181 [[NSTextField alloc] initWithFrame:NSZeroRect]); | |
182 base::string16 label; | |
183 if (!singleRequest) { | |
184 label.push_back(kBulletPoint); | |
185 label.push_back(' '); | |
186 } | |
187 // TODO(leng): Make the appropriate call when it's working. | |
groby-ooo-7-16
2014/01/31 22:31:51
When what is working?
leng
2014/02/03 22:38:04
When the correct text-query function is working.
groby-ooo-7-16
2014/02/04 02:39:29
Much - thank you!
groby-ooo-7-16
2014/02/04 02:39:29
Much - thank you!
| |
188 if (singleRequest) { | |
189 label += request->GetMessageTextFragment(); | |
190 } else { | |
191 label += request->GetMessageTextFragment(); | |
groby-ooo-7-16
2014/01/31 22:31:51
Can that if/else collapse, or is that related to t
leng
2014/02/03 22:38:04
Related to the TODO.
| |
192 } | |
193 [permissionLabel setDrawsBackground:NO]; | |
194 [permissionLabel setBezeled:NO]; | |
195 [permissionLabel setEditable:NO]; | |
196 [permissionLabel setSelectable:NO]; | |
197 [permissionLabel setStringValue:base::SysUTF16ToNSString(label)]; | |
198 [permissionLabel sizeToFit]; | |
199 return permissionLabel.autorelease(); | |
200 } | |
201 | |
202 - (NSView*)titleForMultipleRequests { | |
203 base::scoped_nsobject<NSTextField> titleView( | |
204 [[NSTextField alloc] initWithFrame:NSZeroRect]); | |
205 [titleView setDrawsBackground:NO]; | |
206 [titleView setBezeled:NO]; | |
207 [titleView setEditable:NO]; | |
208 [titleView setSelectable:NO]; | |
209 [titleView setStringValue:@"This site would like to:"]; | |
210 [titleView setFont:[NSFont systemFontOfSize:15.0]]; | |
groby-ooo-7-16
2014/01/31 22:31:51
Might want to call this out as constant
leng
2014/02/03 22:38:04
Done.
| |
211 [titleView sizeToFit]; | |
212 return titleView.autorelease(); | |
213 } | |
214 | |
215 - (NSView*)checkboxForRequest:(PermissionBubbleDelegate*)request | |
216 checked:(BOOL)checked { | |
217 DCHECK(request); | |
218 base::scoped_nsobject<NSButton> checkbox( | |
219 [[NSButton alloc] initWithFrame:NSZeroRect]); | |
220 [checkbox setButtonType:NSSwitchButton]; | |
221 base::string16 permission = request->GetMessageTextFragment(); | |
222 [checkbox setTitle:base::SysUTF16ToNSString(permission)]; | |
223 [checkbox setState:checked ? NSOnState : NSOffState]; | |
groby-ooo-7-16
2014/01/31 22:31:51
nit: Parens around ternary
leng
2014/02/03 22:38:04
Done.
| |
224 [checkbox sizeToFit]; | |
225 [checkbox setFrameOrigin:NSMakePoint(0, kCheckboxYAdjustment)]; | |
226 return checkbox.autorelease(); | |
227 } | |
228 | |
229 - (NSView*)customizationButton { | |
230 NSColor* linkColor = | |
231 gfx::SkColorToCalibratedNSColor(chrome_style::GetLinkColor()); | |
232 base::scoped_nsobject<NSButton> customizeButton( | |
233 [[NSButton alloc] initWithFrame:NSZeroRect]); | |
234 [customizeButton setButtonType:NSMomentaryChangeButton]; | |
235 [customizeButton setAttributedTitle:[[NSAttributedString alloc] | |
236 initWithString:@"Customize" | |
237 attributes:@{ NSForegroundColorAttributeName : linkColor }]]; | |
groby-ooo-7-16
2014/01/31 22:31:51
Is the customizeButton supposed to be an actual li
leng
2014/02/03 22:38:04
I tried that, but not only is it significantly mor
groby-ooo-7-16
2014/02/04 02:39:29
Odd - it should be very simple:
linkView([[HyperL
leng
2014/02/04 21:48:22
So I think I ignored, or glossed over, the questio
| |
238 [customizeButton setTarget:self]; | |
239 [customizeButton setAction:@selector(customize:)]; | |
240 [customizeButton sizeToFit]; | |
241 return customizeButton.autorelease(); | |
242 } | |
243 | |
244 - (NSView*)buttonWithTitle:(NSString*)title | |
245 action:(SEL)action { | |
246 NSRect frame = { {0, 0}, {kButtonWidth, kButtonHeight} }; | |
groby-ooo-7-16
2014/01/31 22:31:51
NSRect frame = NSMakeRect(0, 0, kButtonWidth, kBut
leng
2014/02/03 22:38:04
Done.
| |
247 NSColor* buttonBackgroundColor = | |
248 gfx::SkColorToCalibratedNSColor(SkColorSetRGB(kButtonBackgroundColor, | |
249 kButtonBackgroundColor, | |
250 kButtonBackgroundColor)); | |
251 | |
252 base::scoped_nsobject<NSButton> button( | |
253 [[NSButton alloc] initWithFrame:frame]); | |
254 [button setButtonType:NSMomentaryPushInButton]; | |
255 [button setTitle:title]; | |
256 [button setTarget:self]; | |
257 [button setAction:action]; | |
258 [button setBordered:NO]; | |
259 [[button cell] setBackgroundColor:buttonBackgroundColor]; | |
260 return button.autorelease(); | |
261 } | |
262 | |
263 - (void)ok { | |
264 if (delegate_) | |
groby-ooo-7-16
2014/01/31 22:31:51
I'd prefer a DCHECK delegate_ - I don't think this
leng
2014/02/03 22:38:04
It was when I was first testing - I have an outsta
| |
265 delegate_->Closing(); | |
266 } | |
267 | |
268 - (void)allow { | |
269 if (delegate_) | |
270 delegate_->Accept(); | |
271 } | |
272 | |
273 - (void)block { | |
274 if (delegate_) | |
275 delegate_->Deny(); | |
276 } | |
277 | |
278 - (void)customize { | |
279 if (delegate_) | |
280 delegate_->SetCustomizationMode(); | |
281 } | |
282 | |
283 - (void)checkboxChanged:(id)sender { | |
284 if (!delegate_) | |
285 return; | |
286 auto iter = std::find( | |
287 checkboxes_.begin(), checkboxes_.end(), (NSView*)sender); | |
288 if (iter != checkboxes_.end()) { | |
groby-ooo-7-16
2014/01/31 22:31:51
Again, probably DCHECK. Can never happen
leng
2014/02/03 22:38:04
Done.
| |
289 NSButton *checkbox = (NSButton*)(*iter); | |
groby-ooo-7-16
2014/01/31 22:31:51
base::ObjCCast or base::ObjCCastStrict when castin
leng
2014/02/03 22:38:04
I had no idea about ObjCCast and ObjCCastStrict.
| |
290 delegate_->ToggleAccept(iter - checkboxes_.begin(), | |
291 [checkbox state] == NSOnState); | |
292 } | |
293 } | |
294 | |
295 @end // implementation BookmarkBubbleController(ExposedForUnitTesting) | |
groby-ooo-7-16
2014/01/31 22:31:51
ExposedForUnitTesting?
leng
2014/02/03 22:38:04
BookmarkBubbleController?
Now you know how I start
groby-ooo-7-16
2014/02/04 02:39:29
Heh - I didn't even notice that part. Bad reviewer
groby-ooo-7-16
2014/02/04 02:39:29
Heh - I didn't even notice that part. Bad reviewer
leng
2014/02/04 21:48:22
Am I supposed to pay you with cookies? Are you al
| |
OLD | NEW |