OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 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 <Cocoa/Cocoa.h> |
| 6 |
| 7 #include "base/mac_util.h" |
| 8 #include "base/sys_string_conversions.h" |
| 9 #include "chrome/browser/cocoa/infobar.h" |
| 10 #import "chrome/browser/cocoa/infobar_container_controller.h" |
| 11 #import "chrome/browser/cocoa/infobar_controller.h" |
| 12 #include "chrome/browser/tab_contents/tab_contents.h" |
| 13 #include "skia/ext/skia_utils_mac.h" |
| 14 #include "webkit/glue/window_open_disposition.h" |
| 15 |
| 16 |
| 17 @interface InfoBarController (PrivateMethods) |
| 18 // Closes the infobar by calling RemoveDelegate on the container. |
| 19 // This will remove the infobar from its associated TabContents as |
| 20 // well as trigger the deletion of this InfoBarController. Once the |
| 21 // delegate is removed from the container, it is no longer needed, so |
| 22 // we ask it to delete itself. |
| 23 - (void)closeInfoBar; |
| 24 @end |
| 25 |
| 26 @implementation InfoBarController |
| 27 |
| 28 @synthesize containerController = containerController_; |
| 29 @synthesize delegate = delegate_; |
| 30 |
| 31 - (id)initWithDelegate:(InfoBarDelegate*)delegate { |
| 32 DCHECK(delegate); |
| 33 if ((self = [super initWithNibName:@"InfoBar" |
| 34 bundle:mac_util::MainAppBundle()])) { |
| 35 delegate_ = delegate; |
| 36 } |
| 37 return self; |
| 38 } |
| 39 |
| 40 // All infobars have an icon, so we set up the icon in the base class |
| 41 // awakeFromNib. |
| 42 - (void)awakeFromNib { |
| 43 if (delegate_->GetIcon()) { |
| 44 [image_ setImage:gfx::SkBitmapToNSImage(*(delegate_->GetIcon()))]; |
| 45 } |
| 46 |
| 47 [self addAdditionalControls]; |
| 48 } |
| 49 |
| 50 // Called when someone clicks on the close button. |
| 51 - (void)dismiss:(id)sender { |
| 52 [self closeInfoBar]; |
| 53 } |
| 54 |
| 55 - (void)addAdditionalControls { |
| 56 // Default implementation does nothing. |
| 57 } |
| 58 |
| 59 @end |
| 60 |
| 61 @implementation InfoBarController (PrivateMethods) |
| 62 - (void)closeInfoBar { |
| 63 // Calling RemoveDelegate() triggers notifications which will remove |
| 64 // the infobar view from the infobar container. At that point it is |
| 65 // safe to ask the delegate to delete itself. |
| 66 DCHECK(delegate_); |
| 67 [containerController_ removeDelegate:delegate_]; |
| 68 delegate_->InfoBarClosed(); |
| 69 delegate_ = NULL; |
| 70 } |
| 71 @end |
| 72 |
| 73 |
| 74 ///////////////////////////////////////////////////////////////////////// |
| 75 // AlertInfoBarController implementation |
| 76 |
| 77 @implementation AlertInfoBarController |
| 78 |
| 79 // Alert infobars have a text message. |
| 80 - (void)addAdditionalControls { |
| 81 AlertInfoBarDelegate* delegate = delegate_->AsAlertInfoBarDelegate(); |
| 82 [label_ setStringValue:base::SysWideToNSString( |
| 83 delegate->GetMessageText())]; |
| 84 } |
| 85 |
| 86 @end |
| 87 |
| 88 |
| 89 ///////////////////////////////////////////////////////////////////////// |
| 90 // LinkInfoBarController implementation |
| 91 |
| 92 @implementation LinkInfoBarController |
| 93 |
| 94 // Link infobars have a text message, of which part is linkified. We |
| 95 // use an NSAttributedString to display styled text, and we set a |
| 96 // NSLink attribute on the hyperlink portion of the message. Infobars |
| 97 // use a custom NSTextField subclass, which allows us to override |
| 98 // textView:clickedOnLink:atIndex: and intercept clicks. |
| 99 // |
| 100 // TODO(rohitrao): Using an NSTextField here has some weird UI side |
| 101 // effects, such as showing the wrong cursor at times. Explore other |
| 102 // solutions. |
| 103 - (void)addAdditionalControls { |
| 104 LinkInfoBarDelegate* delegate = delegate_->AsLinkInfoBarDelegate(); |
| 105 size_t offset = std::wstring::npos; |
| 106 std::wstring message = delegate->GetMessageTextWithOffset(&offset); |
| 107 |
| 108 // Create an attributes dictionary for the entire message. We have |
| 109 // to expicitly set the font to the system font, because |
| 110 // NSAttributedString defaults to Helvetica 12. We also override |
| 111 // the cursor to give us the normal cursor rather than the text |
| 112 // insertion cursor. |
| 113 NSMutableDictionary* linkAttributes = |
| 114 [NSMutableDictionary dictionaryWithObject:[NSCursor arrowCursor] |
| 115 forKey:NSCursorAttributeName]; |
| 116 [linkAttributes setObject:[NSFont systemFontOfSize:[NSFont systemFontSize]] |
| 117 forKey:NSFontAttributeName]; |
| 118 |
| 119 // Create the attributed string for the main message text. |
| 120 NSMutableAttributedString* infoText = |
| 121 [[NSMutableAttributedString alloc] |
| 122 initWithString:base::SysWideToNSString(message)]; |
| 123 [infoText addAttributes:linkAttributes |
| 124 range:NSMakeRange(0, [infoText length])]; |
| 125 |
| 126 // Add additional attributes to style the link text appropriately as |
| 127 // well as linkify it. We use an empty string for the NSLink |
| 128 // attribute because the actual object we pass doesn't matter, but |
| 129 // it cannot be nil. |
| 130 [linkAttributes setObject:[NSColor blueColor] |
| 131 forKey:NSForegroundColorAttributeName]; |
| 132 [linkAttributes setObject:[NSNumber numberWithBool:YES] |
| 133 forKey:NSUnderlineStyleAttributeName]; |
| 134 [linkAttributes setObject:[NSCursor pointingHandCursor] |
| 135 forKey:NSCursorAttributeName]; |
| 136 [linkAttributes setObject:[NSString string] // dummy value |
| 137 forKey:NSLinkAttributeName]; |
| 138 |
| 139 // Insert the link text into the string at the appropriate offset. |
| 140 [infoText insertAttributedString: |
| 141 [[[NSAttributedString alloc] |
| 142 initWithString:base::SysWideToNSString(delegate->GetLinkText()) |
| 143 attributes:linkAttributes] autorelease] |
| 144 atIndex:offset]; |
| 145 |
| 146 // Update the label view with the new text. The view must be |
| 147 // selectable and allow editing text attributes for the |
| 148 // linkification to work correctly. |
| 149 [label_ setAllowsEditingTextAttributes: YES]; |
| 150 [label_ setSelectable: YES]; |
| 151 [label_ setAttributedStringValue:infoText]; |
| 152 } |
| 153 |
| 154 // Called when someone clicks on the link in the infobar. This method |
| 155 // is called by the InfobarTextField on its delegate (the |
| 156 // LinkInfoBarController). |
| 157 - (void)linkClicked { |
| 158 // TODO(rohitrao): Set the disposition correctly based on modifier keys. |
| 159 WindowOpenDisposition disposition = CURRENT_TAB; |
| 160 if (delegate_->AsLinkInfoBarDelegate()->LinkClicked(disposition)) |
| 161 [self closeInfoBar]; |
| 162 } |
| 163 |
| 164 @end |
| 165 |
| 166 |
| 167 ///////////////////////////////////////////////////////////////////////// |
| 168 // ConfirmInfoBarController implementation |
| 169 |
| 170 @implementation ConfirmInfoBarController |
| 171 |
| 172 // Called when someone clicks on the "OK" button. |
| 173 - (IBAction)ok:(id)sender { |
| 174 if (delegate_->AsConfirmInfoBarDelegate()->Accept()) |
| 175 [self closeInfoBar]; |
| 176 } |
| 177 |
| 178 // Called when someone clicks on the "Cancel" button. |
| 179 - (IBAction)cancel:(id)sender { |
| 180 if (delegate_->AsConfirmInfoBarDelegate()->Cancel()) |
| 181 [self closeInfoBar]; |
| 182 } |
| 183 |
| 184 // Confirm infobars can have OK and/or cancel buttons, depending on |
| 185 // the return value of GetButtons(). We create each button if |
| 186 // required and position them to the left of the close button. |
| 187 - (void)addAdditionalControls { |
| 188 ConfirmInfoBarDelegate* delegate = delegate_->AsConfirmInfoBarDelegate(); |
| 189 [label_ setStringValue:base::SysWideToNSString(delegate->GetMessageText())]; |
| 190 |
| 191 int visibleButtons = delegate->GetButtons(); |
| 192 NSButton *okButton = nil; |
| 193 NSButton *cancelButton = nil; |
| 194 |
| 195 // Create the OK button if needed. |
| 196 if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK) { |
| 197 okButton = [[[NSButton alloc] initWithFrame:NSZeroRect] autorelease]; |
| 198 [okButton setBezelStyle:NSRoundedBezelStyle]; |
| 199 [okButton setTitle:base::SysWideToNSString( |
| 200 delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK))]; |
| 201 [okButton sizeToFit]; |
| 202 [okButton setAutoresizingMask:NSViewMinXMargin]; |
| 203 [okButton setTarget:self]; |
| 204 [okButton setAction:@selector(ok:)]; |
| 205 } |
| 206 |
| 207 // Create the cancel button if needed. |
| 208 if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) { |
| 209 cancelButton = [[[NSButton alloc] initWithFrame:NSZeroRect] autorelease]; |
| 210 [cancelButton setBezelStyle:NSRoundedBezelStyle]; |
| 211 [cancelButton setTitle:base::SysWideToNSString( |
| 212 delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL))]; |
| 213 [cancelButton sizeToFit]; |
| 214 [cancelButton setAutoresizingMask:NSViewMinXMargin]; |
| 215 [cancelButton setTarget:self]; |
| 216 [cancelButton setAction:@selector(cancel:)]; |
| 217 } |
| 218 |
| 219 // Position the cancel button, if it exists. |
| 220 int cancelWidth = 0; |
| 221 if (cancelButton) { |
| 222 NSRect cancelFrame = [cancelButton frame]; |
| 223 cancelWidth = cancelFrame.size.width + 10; |
| 224 |
| 225 // Position the cancel button to the left of the close button. A 10px |
| 226 // margin is already built into cancelWidth. |
| 227 cancelFrame.origin.x = NSMinX([closeButton_ frame]) - cancelWidth; |
| 228 cancelFrame.origin.y = 0; |
| 229 [cancelButton setFrame:cancelFrame]; |
| 230 [[self view] addSubview:cancelButton]; |
| 231 |
| 232 // Resize the label box to extend all the way to the cancel button, |
| 233 // minus a 10px argin. |
| 234 NSRect labelFrame = [label_ frame]; |
| 235 labelFrame.size.width = NSMinX(cancelFrame) - 10 - NSMinX(labelFrame); |
| 236 [label_ setFrame:labelFrame]; |
| 237 } |
| 238 |
| 239 // Position the OK button, if it exists. |
| 240 if (okButton) { |
| 241 NSRect okFrame = [okButton frame]; |
| 242 int okWidth = okFrame.size.width + 10; |
| 243 |
| 244 // Position the OK button to the left of the close button as |
| 245 // well. If a cancel button is present, |cancelWidth| will be positive. |
| 246 // In either case, a 10px margin is built into okWidth. |
| 247 okFrame.origin.x = |
| 248 NSMinX([closeButton_ frame]) - cancelWidth - okWidth; |
| 249 okFrame.origin.y = 0; |
| 250 [okButton setFrame:okFrame]; |
| 251 [[self view] addSubview:okButton]; |
| 252 |
| 253 // Resize the label box to extend all the way to the OK button, |
| 254 // minus a 10px argin. |
| 255 NSRect labelFrame = [label_ frame]; |
| 256 labelFrame.size.width = NSMinX(okFrame) - 10 - NSMinX(labelFrame); |
| 257 [label_ setFrame:labelFrame]; |
| 258 } |
| 259 } |
| 260 |
| 261 @end |
| 262 |
| 263 |
| 264 ////////////////////////////////////////////////////////////////////////// |
| 265 // CreateInfoBar() implementations |
| 266 |
| 267 InfoBar* AlertInfoBarDelegate::CreateInfoBar() { |
| 268 AlertInfoBarController* controller = |
| 269 [[AlertInfoBarController alloc] initWithDelegate:this]; |
| 270 return new InfoBar(controller); |
| 271 } |
| 272 |
| 273 InfoBar* LinkInfoBarDelegate::CreateInfoBar() { |
| 274 LinkInfoBarController* controller = |
| 275 [[LinkInfoBarController alloc] initWithDelegate:this]; |
| 276 return new InfoBar(controller); |
| 277 } |
| 278 |
| 279 InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() { |
| 280 ConfirmInfoBarController* controller = |
| 281 [[ConfirmInfoBarController alloc] initWithDelegate:this]; |
| 282 return new InfoBar(controller); |
| 283 } |
OLD | NEW |