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

Side by Side Diff: chrome/browser/ui/cocoa/confirm_bubble_view.mm

Issue 8697001: Implement confirm bubble for Mac. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years 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
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/confirm_bubble_view.h"
6
7 #include "base/string16.h"
8 #import "base/mac/cocoa_protocols.h"
9 #include "chrome/browser/themes/theme_service.h"
10 #include "chrome/browser/ui/confirm_bubble_model.h"
11 #import "chrome/browser/ui/cocoa/confirm_bubble_controller.h"
12 //#include "grit/theme_resources.h"
Robert Sesek 2011/12/12 15:42:43 Remove?
Hironori Bono 2011/12/15 13:06:14 Done. Thanks. I forgot removing them after checkin
13 #import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
14 //#include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/image/image.h"
16
17 namespace {
18
19 // The width for the message text. We break lines so the specified message fits
20 // into this width.
21 const int kMaxMessageWidth = 400;
22
23 // The corner redius of this bubble view
Robert Sesek 2011/12/12 15:42:43 nit: full-stop
Hironori Bono 2011/12/15 13:06:14 Done.
24 const int kBubbleCornerRadius = 3;
25
26 // The color for the border of this bubble view.
27 const float kBubbleWindowEdge = 0.7f;
28
29 // Constants used for layouting controls. These variables are copied from
30 // "ui/views/layout/layout_constants.h".
31 // Vertical spacing between a label and some control.
32 const int kLabelToControlVerticalSpacing = 8;
33
34 // Horizontal spacing between controls that are logically related.
35 const int kRelatedControlHorizontalSpacing = 8;
36
37 // Vertical spacing between controls that are logically related.
38 const int kRelatedControlVerticalSpacing = 8;
39
40 // Horizontal spacing between controls that are logically unrelated.
41 const int kUnrelatedControlHorizontalSpacing = 12;
42
43 // Vertical spacing between the edge of the window and the
44 // top or bottom of a button.
45 const int kButtonVEdgeMargin = 6;
46
47 // Horizontal spacing between the edge of the window and the
48 // left or right of a button.
49 const int kButtonHEdgeMargin = 7;
50
51 } // namespace
52
53 // An interface that is derived from NSTextView and does not accept
54 // first-responder status, i.e. a NSTextView-derived class that never becomes
55 // the first responder. When we click a NSTextView object, it becomes the first
56 // responder. Unfortunately, we delete the ConfirmBubbleView object anytime when
57 // it loses first-responder status not to prevent disturbing other responders.
58 // To prevent text views in this ConfirmBubbleView object from stealing the
59 // first-responder status, we use this view in the ConfirmBubbleView object.
60 @interface ConfirmBubbleTextView : NSTextView
61 @end
62
63 @implementation ConfirmBubbleTextView
64
65 - (BOOL)acceptsFirstResponder {
66 return NO;
67 }
68
69 @end
70
71 // Private Methods
72 @interface ConfirmBubbleView(Private)
Robert Sesek 2011/12/12 15:42:43 nit: space before (
Hironori Bono 2011/12/15 13:06:14 Done.
73 - (void)performLayout;
74 - (void)closeBubble;
75 @end
76
77 @implementation ConfirmBubbleView
78
79 - (id)initWithParent:(NSView*)parent
80 controller:(ConfirmBubbleController*)controller {
81 // Create a NSView and set its width. We will set its position and height
82 // after finish layouting controls in performLayout:.
83 NSRect bounds;
Robert Sesek 2011/12/12 15:42:43 Use NSMakeRect
84 bounds.origin.x = bounds.origin.y = 0;
85 bounds.size.width = kMaxMessageWidth + kButtonHEdgeMargin * 2;
86 bounds.size.height = 0;
87 if (self = [super initWithFrame:bounds]) {
88 parent_ = parent;
89 controller_ = controller;
90 [self performLayout];
91 }
92 return self;
93 }
94
95 - (void)drawRect:(NSRect)dirtyRect {
96 // Fill the background rectangle in white and draw its edge.
97 float topLeftRadius = kBubbleCornerRadius;
Robert Sesek 2011/12/12 15:42:43 Any reason why you don't just use the constant as
Hironori Bono 2011/12/15 13:06:14 Done. Sorry, I forgot cleaning up this code after
98 float topRightRadius = kBubbleCornerRadius;
99 float bottomLeftRadius = kBubbleCornerRadius;
100 float bottomRightRadius = kBubbleCornerRadius;
101
102 NSRect bounds = [self bounds];
103 bounds = NSInsetRect(bounds, 0.5, 0.5);
104 NSBezierPath* border =
105 [NSBezierPath gtm_bezierPathWithRoundRect:bounds
106 topLeftCornerRadius:topLeftRadius
107 topRightCornerRadius:topRightRadius
108 bottomLeftCornerRadius:bottomLeftRadius
109 bottomRightCornerRadius:bottomRightRadius];
110
111 [[NSColor colorWithDeviceWhite:1.0f alpha:1.0f] set];
112 [border fill];
113 [[NSColor colorWithDeviceWhite:kBubbleWindowEdge alpha:1.0f] set];
114 [border stroke];
115 }
116
117 // An NSResponder method.
118 - (BOOL)resignFirstResponder {
119 // We do not only accept this request but also close this bubble when we are
120 // asked to resign the first responder. This bubble should be displayed only
121 // while it is the first responder.
122 [self closeBubble];
123 return YES;
124 }
125
126 // NSControl action handlers. These handlers are called when we click a cancel
127 // button, a close icon, and an OK button, respectively.
128 - (IBAction)cancel:(id)sender {
129 [controller_ cancel];
130 [self closeBubble];
131 }
132
133 - (IBAction)close:(id)sender {
134 [self closeBubble];
135 }
136
137 - (IBAction)ok:(id)sender {
138 [controller_ accept];
139 [self closeBubble];
140 }
141
142 // An NSTextViewDelegate method. This function is called when we click a link in
143 // this bubble.
144 - (BOOL)textView:(NSTextView*)textView
145 clickedOnLink:(id)link
146 atIndex:(NSUInteger)charIndex {
147 [controller_ linkClicked];
148 [self closeBubble];
149 return YES;
150 }
151
152 // Initializes controls specified by the ConfirmBubbleModel object and layouts
153 // them into this bubble. This function retrieves text and images from the
154 // ConfirmBubbleModel object (via the ConfirmBubbleController object) and
155 // layouts them programmatically. This function layouts controls in the botom-up
156 // order since NSView uses bottom-up coordinate.
157 - (void)performLayout {
Robert Sesek 2011/12/12 15:42:43 This function may benefit from being broken up int
Hironori Bono 2011/12/15 13:06:14 Thanks for your comment. I would like to keep the
Robert Sesek 2011/12/15 18:47:09 As I said, it's borderline right now, so this is f
158 NSRect frameRect = [self frame];
159
160 // Add the ok button and the cancel button to the first row if we have either
161 // of them.
162 CGFloat left = kButtonHEdgeMargin;
163 CGFloat right = frameRect.size.width - kButtonHEdgeMargin;
164 CGFloat bottom = kButtonVEdgeMargin;
165 CGFloat height = 0;
166 if ([controller_ hasOkButton]) {
167 okButton_.reset([[NSButton alloc]
168 initWithFrame:NSMakeRect(0, bottom, 0, 0)]);
169 [okButton_.get() setBezelStyle:NSRoundedBezelStyle];
170 [okButton_.get() setTitle:[controller_ okButton]];
171 [okButton_.get() setTarget:self];
172 [okButton_.get() setAction:@selector(ok:)];
173 [okButton_.get() sizeToFit];
174 NSRect okButtonRect = [okButton_.get() frame];
175 right -= okButtonRect.size.width;
176 okButtonRect.origin.x = right;
177 [okButton_.get() setFrame:okButtonRect];
178 [self addSubview:okButton_.get()];
179 height = std::max(height, okButtonRect.size.height);
180 }
181 if ([controller_ hasCancelButton]) {
182 cancelButton_.reset([[NSButton alloc]
183 initWithFrame:NSMakeRect(0, bottom, 0, 0)]);
184 [cancelButton_.get() setBezelStyle:NSRoundedBezelStyle];
185 [cancelButton_.get() setTitle:[controller_ cancelButton]];
186 [cancelButton_.get() setTarget:self];
187 [cancelButton_.get() setAction:@selector(cancel:)];
188 [cancelButton_.get() sizeToFit];
189 NSRect cancelButtonRect = [cancelButton_.get() frame];
190 right -= cancelButtonRect.size.width + kButtonHEdgeMargin;
191 cancelButtonRect.origin.x = right;
192 [cancelButton_.get() setFrame:cancelButtonRect];
193 [self addSubview:cancelButton_.get()];
194 height = std::max(height, cancelButtonRect.size.height);
195 }
196
197 // Add the message label (and the link label) to the second row.
198 left = kButtonHEdgeMargin;
199 right = frameRect.size.width;
200 bottom += height + kRelatedControlVerticalSpacing;
201 height = 0;
202 messageLabel_.reset([[ConfirmBubbleTextView alloc]
203 initWithFrame:NSMakeRect(left, bottom, kMaxMessageWidth, 0)]);
204 NSString* messageText = [controller_ messageText];
205 NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
206 scoped_nsobject<NSMutableAttributedString> attributedMessage(
207 [[NSMutableAttributedString alloc] initWithString:messageText
208 attributes:attributes]);
209 NSString* linkText = [controller_ linkText];
210 if (linkText) {
211 [attributes setObject:[NSString string]
212 forKey:NSLinkAttributeName];
213 scoped_nsobject<NSAttributedString> attributedLink(
214 [[NSAttributedString alloc] initWithString:linkText
215 attributes:attributes]);
216 [attributedMessage.get() appendAttributedString:attributedLink.get()];
217 }
218 [[messageLabel_.get() textStorage] setAttributedString:attributedMessage];
219 [messageLabel_.get() setHorizontallyResizable:NO];
220 [messageLabel_.get() setVerticallyResizable:YES];
221 [messageLabel_.get() setEditable:NO];
222 [messageLabel_.get() setDrawsBackground:NO];
223 [messageLabel_.get() setDelegate:self];
224 [messageLabel_.get() sizeToFit];
225 height = [messageLabel_.get() frame].size.height;
226 [self addSubview:messageLabel_.get()];
227
228 // Add the icon and the title label to the third row.
229 left = kButtonHEdgeMargin;
230 right = frameRect.size.width;
231 bottom += height + kLabelToControlVerticalSpacing;
232 height = 0;
233 NSImage* iconImage = [controller_ icon];
234 if (iconImage) {
235 icon_.reset([[NSImageView alloc] initWithFrame:NSMakeRect(
236 left, bottom, [iconImage size].width,[iconImage size].height)]);
Robert Sesek 2011/12/12 15:42:43 nit: space after ,
Hironori Bono 2011/12/15 13:06:14 Done.
237 [icon_.get() setImage:iconImage];
238 [self addSubview:icon_.get()];
239 left += [icon_.get() frame].size.width + kRelatedControlHorizontalSpacing;
240 height = std::max(height, [icon_.get() frame].size.height);
241 }
242 titleLabel_.reset([[NSTextView alloc]
243 initWithFrame:NSMakeRect(left, bottom, right - left, 0)]);
244 [titleLabel_.get() setString:[controller_ title]];
245 [titleLabel_.get() setHorizontallyResizable:NO];
246 [titleLabel_.get() setVerticallyResizable:YES];
247 [titleLabel_.get() setEditable:NO];
248 [titleLabel_.get() setSelectable:NO];
249 [titleLabel_.get() setDrawsBackground:NO];
250 [titleLabel_.get() sizeToFit];
251 [self addSubview:titleLabel_.get()];
252 height = std::max(height, [titleLabel_.get() frame].size.height);
253
254 // Adjust the frame rectangle of this bubble so we can show all controls.
255 NSRect parentRect = [parent_ frame];
256 frameRect.size.height = bottom + height + kButtonVEdgeMargin;
257 frameRect.origin.x = (parentRect.size.width - frameRect.size.width) / 2;
258 frameRect.origin.y = parentRect.size.height - frameRect.size.height;
259 [self setFrame:frameRect];
260 }
261
262 // Closes this bubble and releases all resources. This function just puts the
263 // owner ConfirmBubbleController object to the current autorelease pool. (This
264 // view will be deleted when the owner object is deleted.)
265 - (void)closeBubble {
266 [self removeFromSuperview];
267 [controller_ autorelease];
268 parent_ = nil;
269 controller_ = nil;
270 }
271
272 @end
273
274 @implementation ConfirmBubbleView(ExposedForUnitTesting)
Robert Sesek 2011/12/12 15:42:43 nit: space after (
Hironori Bono 2011/12/15 13:06:14 Does this mean 'before (' as written above?
275
276 - (void)clickOk {
277 [self ok:self];
278 }
279
280 - (void)clickCancel {
281 [self cancel:self];
282 }
283
284 - (void)clickLink {
285 [self textView:messageLabel_.get() clickedOnLink:nil atIndex:0];
286 }
287
288 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698