Chromium Code Reviews
|
| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |