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

Side by Side Diff: chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm

Issue 151593005: Implement permission bubble view for Cocoa. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed variable name Created 6 years, 10 months 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
(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/website_settings/permission_bubble_controller.h "
6
7 #include <algorithm>
8
9 #include "base/mac/foundation_util.h"
10 #include "base/mac/mac_util.h"
11 #include "base/strings/sys_string_conversions.h"
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/constrained_window/constrained_window_button.h"
17 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
18 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
19 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
20 #include "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h"
21 #include "chrome/browser/ui/website_settings/permission_bubble_delegate.h"
22 #include "chrome/browser/ui/website_settings/permission_bubble_view.h"
23 #include "content/public/browser/user_metrics.h"
24 #include "grit/generated_resources.h"
25 #include "skia/ext/skia_utils_mac.h"
26 #include "ui/base/l10n/l10n_util_mac.h"
27
28 using base::UserMetricsAction;
29
30 namespace {
31 const CGFloat kHorizontalPadding = 20.0f;
32 const CGFloat kVerticalPadding = 20.0f;
33 const CGFloat kButtonPadding = 10.0f;
34 const CGFloat kCheckboxYAdjustment = 2.0f;
35
36 const CGFloat kButtonWidth = 80.0f;
37 const CGFloat kButtonHeight = 30.0f;
38
39 const CGFloat kFontSize = 15.0f;
40 const base::char16 kBulletPoint = 0x2022;
41
42 } // namespace
43
44 @interface PermissionBubbleController ()
45
46 // Called when the 'ok' button is pressed.
47 - (void)ok:(id)sender;
48
49 // Called when the 'allow' button is pressed.
50 - (void)onAllow:(id)sender;
51
52 // Called when the 'block' button is pressed.
53 - (void)onBlock:(id)sender;
54
55 // Called when the 'customize' button is pressed.
56 - (void)onCustomize:(id)sender;
57
58 // Called when a checkbox changes from checked to unchecked, or vice versa.
59 - (void)onCheckboxChanged:(id)sender;
60
61 @end
62
63 @implementation PermissionBubbleController
64
65 - (id)initWithParentWindow:(NSWindow*)parentWindow
66 bridge:(PermissionBubbleCocoa*)bridge {
67 DCHECK(parentWindow);
68 DCHECK(bridge);
69 base::scoped_nsobject<InfoBubbleWindow> window(
70 [[InfoBubbleWindow alloc] initWithContentRect:NSMakeRect(0, 0, 240, 150)
groby-ooo-7-16 2014/02/11 20:10:06 nit: since showAtAnchor computes a new window size
leng 2014/02/11 22:45:48 Done.
71 styleMask:NSBorderlessWindowMask
72 backing:NSBackingStoreBuffered
73 defer:NO]);
74 [window setAllowedAnimations:info_bubble::kAnimateNone];
75 if ((self = [super initWithWindow:window
76 parentWindow:parentWindow
77 anchoredAt:NSZeroPoint])) {
78 [self setShouldCloseOnResignKey:NO];
79 [[self bubble] setArrowLocation:info_bubble::kTopLeft];
80 bridge_ = bridge;
81 }
82 return self;
83 }
84
85 - (void)windowWillClose:(NSNotification*)notification {
86 bridge_->OnBubbleClosing();
87 [super windowWillClose:notification];
88 }
89
90 - (void)showAtAnchor:(NSPoint)anchorPoint
91 withDelegate:(PermissionBubbleView::Delegate*)delegate
92 forRequests:(const std::vector<PermissionBubbleDelegate*>&)requests
93 acceptStates:(const std::vector<bool>&)acceptStates
94 customizationMode:(BOOL)customizationMode {
95 DCHECK(delegate);
96 DCHECK(!customizationMode || (requests.size() == acceptStates.size()));
97 delegate_ = delegate;
98
99 NSView* contentView = [[self window] contentView];
100 DCHECK([[contentView subviews] count] == 0);
101
102 BOOL singlePermission = requests.size() == 1;
103 NSRect bubbleFrame = [[self window] frame];
groby-ooo-7-16 2014/02/11 20:10:06 [[self window] contentRectForFrameRect:[[self wind
leng 2014/02/11 22:45:48 I used NSZeroRect and added padding for it with th
104 CGFloat yOffset = 2 * kVerticalPadding + kButtonHeight;
105
106 checkboxes_.reset(customizationMode ? [[NSMutableArray alloc] init] : nil);
107 for (auto it = requests.begin(); it != requests.end(); it++) {
108 base::scoped_nsobject<NSView> permissionView;
109 if (customizationMode) {
110 int index = it - requests.begin();
111 permissionView.reset(
112 [[self checkboxForRequest:(*it)
113 checked:acceptStates[index] ? YES : NO] retain]);
114 [base::mac::ObjCCastStrict<NSButton>(permissionView)
115 setTag:(it - requests.begin())];
groby-ooo-7-16 2014/02/11 20:10:06 setTag:index
leng 2014/02/11 22:45:48 Done.
116 [checkboxes_ addObject:permissionView];
117 } else {
118 permissionView.reset([[self labelForRequest:(*it)
119 isSingleRequest:singlePermission] retain]);
120 }
121 NSPoint origin = [permissionView frame].origin;
122 origin.x += kHorizontalPadding;
123 origin.y += yOffset;
124 [permissionView setFrameOrigin:origin];
125 [contentView addSubview:permissionView];
126
127 yOffset += NSHeight([permissionView frame]);
128 }
129
130 if (!singlePermission && !customizationMode) {
131 base::scoped_nsobject<NSView> customizeButton(
132 [[self customizationButton] retain]);
133 // The Y center should match the Y centers of the buttons.
134 CGFloat customizeButtonYOffset = kVerticalPadding +
135 (kButtonHeight - std::ceil(NSHeight([customizeButton frame])) * 0.5f);
groby-ooo-7-16 2014/02/11 20:10:06 I think the braces for ceil are off - you want to
leng 2014/02/11 22:45:48 Good catch! The ceil() was off, actually. Fixed.
136 [customizeButton setFrameOrigin:NSMakePoint(kHorizontalPadding,
137 customizeButtonYOffset)];
138 [contentView addSubview:customizeButton];
139 }
140
141 // The maximum width of the above permissions will dictate the width of the
142 // bubble. It is calculated here so that it can be used for the positioning
143 // of the buttons.
144 for (NSView* view in [contentView subviews])
145 bubbleFrame = NSUnionRect(bubbleFrame, [view frame]);
146
147 base::scoped_nsobject<NSView> allowOrOkButton;
148 if (customizationMode) {
149 allowOrOkButton.reset([[self buttonWithTitle:@"OK"
groby-ooo-7-16 2014/02/11 20:10:06 You should at some point i18n the text constants -
leng 2014/02/11 22:45:48 Yup, will do asap in a follow-up CL.
150 action:@selector(ok:)] retain]);
151 } else {
152 allowOrOkButton.reset([[self buttonWithTitle:@"Allow"
153 action:@selector(onAllow:)] retain]);
154 }
155 CGFloat xOrigin = NSWidth(bubbleFrame) - kButtonWidth - kHorizontalPadding;
156 [allowOrOkButton setFrameOrigin:NSMakePoint(xOrigin, kVerticalPadding)];
157 [contentView addSubview:allowOrOkButton];
158
159 if (!customizationMode) {
160 base::scoped_nsobject<NSView> blockButton(
161 [[self buttonWithTitle:@"Block" action:@selector(onBlock:)] retain]);
162 xOrigin = NSMinX([allowOrOkButton frame]) - NSWidth([blockButton frame]) -
163 kButtonPadding;
164 [blockButton setFrameOrigin:NSMakePoint(xOrigin, kVerticalPadding)];
165 [contentView addSubview:blockButton];
166 }
167
168 if (!singlePermission) {
169 base::scoped_nsobject<NSView> titleView(
170 [[self titleForMultipleRequests] retain]);
171 [contentView addSubview:titleView];
172 [titleView setFrameOrigin:NSMakePoint(kHorizontalPadding,
173 kVerticalPadding + yOffset)];
174 yOffset += NSHeight([titleView frame]) + kVerticalPadding;
175 }
176
177 bubbleFrame.size.height = yOffset + kVerticalPadding;
178 bubbleFrame = [[self window] frameRectForContentRect:bubbleFrame];
179 [[self window] setFrame:bubbleFrame display:NO];
180
181 [self setAnchorPoint:anchorPoint];
182 [self showWindow:nil];
183 }
184
185 - (NSView*)labelForRequest:(PermissionBubbleDelegate*)request
186 isSingleRequest:(BOOL)singleRequest {
187 DCHECK(request);
188 base::scoped_nsobject<NSTextField> permissionLabel(
189 [[NSTextField alloc] initWithFrame:NSZeroRect]);
190 base::string16 label;
191 if (!singleRequest) {
192 label.push_back(kBulletPoint);
193 label.push_back(' ');
194 }
195 if (singleRequest) {
196 // TODO(leng): Make the appropriate call when it's working. It should call
197 // GetMessageText(), but it's not returning the correct string yet.
198 label += request->GetMessageTextFragment();
199 } else {
200 label += request->GetMessageTextFragment();
201 }
202 [permissionLabel setDrawsBackground:NO];
203 [permissionLabel setBezeled:NO];
204 [permissionLabel setEditable:NO];
205 [permissionLabel setSelectable:NO];
206 [permissionLabel setStringValue:base::SysUTF16ToNSString(label)];
207 [permissionLabel sizeToFit];
208 return permissionLabel.autorelease();
209 }
210
211 - (NSView*)titleForMultipleRequests {
212 base::scoped_nsobject<NSTextField> titleView(
213 [[NSTextField alloc] initWithFrame:NSZeroRect]);
214 [titleView setDrawsBackground:NO];
215 [titleView setBezeled:NO];
216 [titleView setEditable:NO];
217 [titleView setSelectable:NO];
218 [titleView setStringValue:@"This site would like to:"];
219 [titleView setFont:[NSFont systemFontOfSize:kFontSize]];
220 [titleView sizeToFit];
221 return titleView.autorelease();
222 }
223
224 - (NSView*)checkboxForRequest:(PermissionBubbleDelegate*)request
225 checked:(BOOL)checked {
226 DCHECK(request);
227 base::scoped_nsobject<NSButton> checkbox(
228 [[NSButton alloc] initWithFrame:NSZeroRect]);
229 [checkbox setButtonType:NSSwitchButton];
230 base::string16 permission = request->GetMessageTextFragment();
231 [checkbox setTitle:base::SysUTF16ToNSString(permission)];
232 [checkbox setState:(checked ? NSOnState : NSOffState)];
233 [checkbox setTarget:self];
234 [checkbox setAction:@selector(onCheckboxChanged:)];
235 [checkbox sizeToFit];
236 [checkbox setFrameOrigin:NSMakePoint(0, kCheckboxYAdjustment)];
groby-ooo-7-16 2014/02/11 20:10:06 since you're setting the permissionView's origin,
leng 2014/02/11 22:45:48 Yes - the calling function just adds to the existi
237 return checkbox.autorelease();
238 }
239
240 - (NSView*)customizationButton {
241 NSColor* linkColor =
242 gfx::SkColorToCalibratedNSColor(chrome_style::GetLinkColor());
243 base::scoped_nsobject<NSButton> customizeButton(
244 [[NSButton alloc] initWithFrame:NSZeroRect]);
245 [customizeButton setButtonType:NSMomentaryChangeButton];
246 [customizeButton setAttributedTitle:[[NSAttributedString alloc]
247 initWithString:@"Customize"
248 attributes:@{ NSForegroundColorAttributeName : linkColor }]];
249 [customizeButton setTarget:self];
250 [customizeButton setAction:@selector(onCustomize:)];
251 [customizeButton setBordered:NO];
252 [customizeButton sizeToFit];
253 return customizeButton.autorelease();
254 }
255
256 - (NSView*)buttonWithTitle:(NSString*)title
257 action:(SEL)action {
258 NSRect frame = NSMakeRect(0, 0, kButtonWidth, kButtonHeight);
groby-ooo-7-16 2014/02/11 20:10:06 N.B.: This will break for internationalized string
leng 2014/02/11 22:45:48 Good catch. Done.
259 base::scoped_nsobject<NSButton> button(
260 [[ConstrainedWindowButton alloc] initWithFrame:frame]);
261 [button setButtonType:NSMomentaryPushInButton];
262 [button setTitle:title];
263 [button setTarget:self];
264 [button setAction:action];
265 return button.autorelease();
266 }
267
268 - (void)ok:(id)sender {
269 DCHECK(delegate_);
270 delegate_->Closing();
271 }
272
273 - (void)onAllow:(id)sender {
274 DCHECK(delegate_);
275 delegate_->Accept();
276 }
277
278 - (void)onBlock:(id)sender {
279 DCHECK(delegate_);
280 delegate_->Deny();
281 }
282
283 - (void)onCustomize:(id)sender {
284 DCHECK(delegate_);
285 delegate_->SetCustomizationMode();
286 }
287
288 - (void)onCheckboxChanged:(id)sender {
289 DCHECK(delegate_);
290 NSButton* checkbox = base::mac::ObjCCastStrict<NSButton>(sender);
291 delegate_->ToggleAccept([checkbox tag], [checkbox state] == NSOnState);
292 }
293
294 @end // implementation PermissionBubbleController
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698