| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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/logging.h" // for NOTREACHED() | |
| 8 #include "base/mac/mac_util.h" | |
| 9 #include "base/sys_string_conversions.h" | |
| 10 #include "chrome/browser/tab_contents/infobar_delegate.h" | |
| 11 #import "chrome/browser/ui/cocoa/animatable_view.h" | |
| 12 #include "chrome/browser/ui/cocoa/event_utils.h" | |
| 13 #include "chrome/browser/ui/cocoa/infobar.h" | |
| 14 #import "chrome/browser/ui/cocoa/infobar_container_controller.h" | |
| 15 #import "chrome/browser/ui/cocoa/infobar_controller.h" | |
| 16 #include "skia/ext/skia_utils_mac.h" | |
| 17 #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" | |
| 18 #include "webkit/glue/window_open_disposition.h" | |
| 19 | |
| 20 namespace { | |
| 21 // Durations set to match the default SlideAnimation duration. | |
| 22 const float kAnimateOpenDuration = 0.12; | |
| 23 const float kAnimateCloseDuration = 0.12; | |
| 24 } | |
| 25 | |
| 26 // This simple subclass of |NSTextView| just doesn't show the (text) cursor | |
| 27 // (|NSTextView| displays the cursor with full keyboard accessibility enabled). | |
| 28 @interface InfoBarTextView : NSTextView | |
| 29 - (void)fixupCursor; | |
| 30 @end | |
| 31 | |
| 32 @implementation InfoBarTextView | |
| 33 | |
| 34 // Never draw the insertion point (otherwise, it shows up without any user | |
| 35 // action if full keyboard accessibility is enabled). | |
| 36 - (BOOL)shouldDrawInsertionPoint { | |
| 37 return NO; | |
| 38 } | |
| 39 | |
| 40 - (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange | |
| 41 granularity:(NSSelectionGranularity)granularity { | |
| 42 // Do not allow selections. | |
| 43 return NSMakeRange(0, 0); | |
| 44 } | |
| 45 | |
| 46 // Convince NSTextView to not show an I-Beam cursor when the cursor is over the | |
| 47 // text view but not over actual text. | |
| 48 // | |
| 49 // http://www.mail-archive.com/cocoa-dev@lists.apple.com/msg10791.html | |
| 50 // "NSTextView sets the cursor over itself dynamically, based on considerations | |
| 51 // including the text under the cursor. It does so in -mouseEntered:, | |
| 52 // -mouseMoved:, and -cursorUpdate:, so those would be points to consider | |
| 53 // overriding." | |
| 54 - (void)mouseMoved:(NSEvent*)e { | |
| 55 [super mouseMoved:e]; | |
| 56 [self fixupCursor]; | |
| 57 } | |
| 58 | |
| 59 - (void)mouseEntered:(NSEvent*)e { | |
| 60 [super mouseEntered:e]; | |
| 61 [self fixupCursor]; | |
| 62 } | |
| 63 | |
| 64 - (void)cursorUpdate:(NSEvent*)e { | |
| 65 [super cursorUpdate:e]; | |
| 66 [self fixupCursor]; | |
| 67 } | |
| 68 | |
| 69 - (void)fixupCursor { | |
| 70 if ([[NSCursor currentCursor] isEqual:[NSCursor IBeamCursor]]) | |
| 71 [[NSCursor arrowCursor] set]; | |
| 72 } | |
| 73 | |
| 74 @end | |
| 75 | |
| 76 @interface InfoBarController (PrivateMethods) | |
| 77 // Sets |label_| based on |labelPlaceholder_|, sets |labelPlaceholder_| to nil. | |
| 78 - (void)initializeLabel; | |
| 79 | |
| 80 // Asks the container controller to remove the infobar for this delegate. This | |
| 81 // call will trigger a notification that starts the infobar animating closed. | |
| 82 - (void)removeInfoBar; | |
| 83 | |
| 84 // Performs final cleanup after an animation is finished or stopped, including | |
| 85 // notifying the InfoBarDelegate that the infobar was closed and removing the | |
| 86 // infobar from its container, if necessary. | |
| 87 - (void)cleanUpAfterAnimation:(BOOL)finished; | |
| 88 | |
| 89 // Sets the info bar message to the specified |message|, with a hypertext | |
| 90 // style link. |link| will be inserted into message at |linkOffset|. | |
| 91 - (void)setLabelToMessage:(NSString*)message | |
| 92 withLink:(NSString*)link | |
| 93 atOffset:(NSUInteger)linkOffset; | |
| 94 @end | |
| 95 | |
| 96 @implementation InfoBarController | |
| 97 | |
| 98 @synthesize containerController = containerController_; | |
| 99 @synthesize delegate = delegate_; | |
| 100 | |
| 101 - (id)initWithDelegate:(InfoBarDelegate*)delegate { | |
| 102 DCHECK(delegate); | |
| 103 if ((self = [super initWithNibName:@"InfoBar" | |
| 104 bundle:base::mac::MainAppBundle()])) { | |
| 105 delegate_ = delegate; | |
| 106 } | |
| 107 return self; | |
| 108 } | |
| 109 | |
| 110 // All infobars have an icon, so we set up the icon in the base class | |
| 111 // awakeFromNib. | |
| 112 - (void)awakeFromNib { | |
| 113 DCHECK(delegate_); | |
| 114 if (delegate_->GetIcon()) { | |
| 115 [image_ setImage:gfx::SkBitmapToNSImage(*(delegate_->GetIcon()))]; | |
| 116 } else { | |
| 117 // No icon, remove it from the view and grow the textfield to include the | |
| 118 // space. | |
| 119 NSRect imageFrame = [image_ frame]; | |
| 120 NSRect labelFrame = [labelPlaceholder_ frame]; | |
| 121 labelFrame.size.width += NSMinX(imageFrame) - NSMinX(labelFrame); | |
| 122 labelFrame.origin.x = imageFrame.origin.x; | |
| 123 [image_ removeFromSuperview]; | |
| 124 [labelPlaceholder_ setFrame:labelFrame]; | |
| 125 } | |
| 126 [self initializeLabel]; | |
| 127 | |
| 128 [self addAdditionalControls]; | |
| 129 } | |
| 130 | |
| 131 // Called when someone clicks on the embedded link. | |
| 132 - (BOOL) textView:(NSTextView*)textView | |
| 133 clickedOnLink:(id)link | |
| 134 atIndex:(NSUInteger)charIndex { | |
| 135 if ([self respondsToSelector:@selector(linkClicked)]) | |
| 136 [self performSelector:@selector(linkClicked)]; | |
| 137 return YES; | |
| 138 } | |
| 139 | |
| 140 // Called when someone clicks on the ok button. | |
| 141 - (void)ok:(id)sender { | |
| 142 // Subclasses must override this method if they do not hide the ok button. | |
| 143 NOTREACHED(); | |
| 144 } | |
| 145 | |
| 146 // Called when someone clicks on the cancel button. | |
| 147 - (void)cancel:(id)sender { | |
| 148 // Subclasses must override this method if they do not hide the cancel button. | |
| 149 NOTREACHED(); | |
| 150 } | |
| 151 | |
| 152 // Called when someone clicks on the close button. | |
| 153 - (void)dismiss:(id)sender { | |
| 154 [self removeInfoBar]; | |
| 155 } | |
| 156 | |
| 157 - (AnimatableView*)animatableView { | |
| 158 return static_cast<AnimatableView*>([self view]); | |
| 159 } | |
| 160 | |
| 161 - (void)open { | |
| 162 // Simply reset the frame size to its opened size, forcing a relayout. | |
| 163 CGFloat finalHeight = [[self view] frame].size.height; | |
| 164 [[self animatableView] setHeight:finalHeight]; | |
| 165 } | |
| 166 | |
| 167 - (void)animateOpen { | |
| 168 // Force the frame size to be 0 and then start an animation. | |
| 169 NSRect frame = [[self view] frame]; | |
| 170 CGFloat finalHeight = frame.size.height; | |
| 171 frame.size.height = 0; | |
| 172 [[self view] setFrame:frame]; | |
| 173 [[self animatableView] animateToNewHeight:finalHeight | |
| 174 duration:kAnimateOpenDuration]; | |
| 175 } | |
| 176 | |
| 177 - (void)close { | |
| 178 // Stop any running animations. | |
| 179 [[self animatableView] stopAnimation]; | |
| 180 infoBarClosing_ = YES; | |
| 181 [self cleanUpAfterAnimation:YES]; | |
| 182 } | |
| 183 | |
| 184 - (void)animateClosed { | |
| 185 // Start animating closed. We will receive a notification when the animation | |
| 186 // is done, at which point we can remove our view from the hierarchy and | |
| 187 // notify the delegate that the infobar was closed. | |
| 188 [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration]; | |
| 189 | |
| 190 // The above call may trigger an animationDidStop: notification for any | |
| 191 // currently-running animations, so do not set |infoBarClosing_| until after | |
| 192 // starting the animation. | |
| 193 infoBarClosing_ = YES; | |
| 194 } | |
| 195 | |
| 196 - (void)addAdditionalControls { | |
| 197 // Default implementation does nothing. | |
| 198 } | |
| 199 | |
| 200 - (void)infobarWillClose { | |
| 201 // Default implementation does nothing. | |
| 202 } | |
| 203 | |
| 204 - (void)setLabelToMessage:(NSString*)message { | |
| 205 NSMutableDictionary* attributes = [NSMutableDictionary dictionary]; | |
| 206 NSFont* font = [NSFont labelFontOfSize: | |
| 207 [NSFont systemFontSizeForControlSize:NSRegularControlSize]]; | |
| 208 [attributes setObject:font | |
| 209 forKey:NSFontAttributeName]; | |
| 210 [attributes setObject:[NSCursor arrowCursor] | |
| 211 forKey:NSCursorAttributeName]; | |
| 212 scoped_nsobject<NSAttributedString> attributedString( | |
| 213 [[NSAttributedString alloc] initWithString:message | |
| 214 attributes:attributes]); | |
| 215 [[label_.get() textStorage] setAttributedString:attributedString]; | |
| 216 } | |
| 217 | |
| 218 - (void)removeButtons { | |
| 219 // Extend the label all the way across. | |
| 220 NSRect labelFrame = [label_.get() frame]; | |
| 221 labelFrame.size.width = NSMaxX([cancelButton_ frame]) - NSMinX(labelFrame); | |
| 222 [okButton_ removeFromSuperview]; | |
| 223 [cancelButton_ removeFromSuperview]; | |
| 224 [label_.get() setFrame:labelFrame]; | |
| 225 } | |
| 226 | |
| 227 @end | |
| 228 | |
| 229 @implementation InfoBarController (PrivateMethods) | |
| 230 | |
| 231 - (void)initializeLabel { | |
| 232 // Replace the label placeholder NSTextField with the real label NSTextView. | |
| 233 // The former doesn't show links in a nice way, but the latter can't be added | |
| 234 // in IB without a containing scroll view, so create the NSTextView | |
| 235 // programmatically. | |
| 236 label_.reset([[InfoBarTextView alloc] | |
| 237 initWithFrame:[labelPlaceholder_ frame]]); | |
| 238 [label_.get() setAutoresizingMask:[labelPlaceholder_ autoresizingMask]]; | |
| 239 [[labelPlaceholder_ superview] | |
| 240 replaceSubview:labelPlaceholder_ with:label_.get()]; | |
| 241 labelPlaceholder_ = nil; // Now released. | |
| 242 [label_.get() setDelegate:self]; | |
| 243 [label_.get() setEditable:NO]; | |
| 244 [label_.get() setDrawsBackground:NO]; | |
| 245 [label_.get() setHorizontallyResizable:NO]; | |
| 246 [label_.get() setVerticallyResizable:NO]; | |
| 247 } | |
| 248 | |
| 249 - (void)removeInfoBar { | |
| 250 // TODO(rohitrao): This method can be called even if the infobar has already | |
| 251 // been removed and |delegate_| is NULL. Is there a way to rewrite the code | |
| 252 // so that inner event loops don't cause us to try and remove the infobar | |
| 253 // twice? http://crbug.com/54253 | |
| 254 [containerController_ removeDelegate:delegate_]; | |
| 255 } | |
| 256 | |
| 257 - (void)cleanUpAfterAnimation:(BOOL)finished { | |
| 258 // Don't need to do any cleanup if the bar was animating open. | |
| 259 if (!infoBarClosing_) | |
| 260 return; | |
| 261 | |
| 262 // Notify the delegate that the infobar was closed. The delegate may delete | |
| 263 // itself as a result of InfoBarClosed(), so we null out its pointer. | |
| 264 if (delegate_) { | |
| 265 delegate_->InfoBarClosed(); | |
| 266 delegate_ = NULL; | |
| 267 } | |
| 268 | |
| 269 // If the animation ran to completion, then we need to remove ourselves from | |
| 270 // the container. If the animation was interrupted, then the container will | |
| 271 // take care of removing us. | |
| 272 // TODO(rohitrao): UGH! This works for now, but should be cleaner. | |
| 273 if (finished) | |
| 274 [containerController_ removeController:self]; | |
| 275 } | |
| 276 | |
| 277 - (void)animationDidStop:(NSAnimation*)animation { | |
| 278 [self cleanUpAfterAnimation:NO]; | |
| 279 } | |
| 280 | |
| 281 - (void)animationDidEnd:(NSAnimation*)animation { | |
| 282 [self cleanUpAfterAnimation:YES]; | |
| 283 } | |
| 284 | |
| 285 // TODO(joth): This method factors out some common functionality between the | |
| 286 // various derived infobar classes, however the class hierarchy itself could | |
| 287 // use refactoring to reduce this duplication. http://crbug.com/38924 | |
| 288 - (void)setLabelToMessage:(NSString*)message | |
| 289 withLink:(NSString*)link | |
| 290 atOffset:(NSUInteger)linkOffset { | |
| 291 if (linkOffset == std::wstring::npos) { | |
| 292 // linkOffset == std::wstring::npos means the link should be right-aligned, | |
| 293 // which is not supported on Mac (http://crbug.com/47728). | |
| 294 NOTIMPLEMENTED(); | |
| 295 linkOffset = [message length]; | |
| 296 } | |
| 297 // Create an attributes dictionary for the entire message. We have | |
| 298 // to expicitly set the font the control's font. We also override | |
| 299 // the cursor to give us the normal cursor rather than the text | |
| 300 // insertion cursor. | |
| 301 NSMutableDictionary* linkAttributes = [NSMutableDictionary dictionary]; | |
| 302 [linkAttributes setObject:[NSCursor arrowCursor] | |
| 303 forKey:NSCursorAttributeName]; | |
| 304 NSFont* font = [NSFont labelFontOfSize: | |
| 305 [NSFont systemFontSizeForControlSize:NSRegularControlSize]]; | |
| 306 [linkAttributes setObject:font | |
| 307 forKey:NSFontAttributeName]; | |
| 308 | |
| 309 // Create the attributed string for the main message text. | |
| 310 scoped_nsobject<NSMutableAttributedString> infoText( | |
| 311 [[NSMutableAttributedString alloc] initWithString:message]); | |
| 312 [infoText.get() addAttributes:linkAttributes | |
| 313 range:NSMakeRange(0, [infoText.get() length])]; | |
| 314 // Add additional attributes to style the link text appropriately as | |
| 315 // well as linkify it. | |
| 316 [linkAttributes setObject:[NSColor blueColor] | |
| 317 forKey:NSForegroundColorAttributeName]; | |
| 318 [linkAttributes setObject:[NSNumber numberWithBool:YES] | |
| 319 forKey:NSUnderlineStyleAttributeName]; | |
| 320 [linkAttributes setObject:[NSCursor pointingHandCursor] | |
| 321 forKey:NSCursorAttributeName]; | |
| 322 [linkAttributes setObject:[NSNumber numberWithInt:NSSingleUnderlineStyle] | |
| 323 forKey:NSUnderlineStyleAttributeName]; | |
| 324 [linkAttributes setObject:[NSString string] // dummy value | |
| 325 forKey:NSLinkAttributeName]; | |
| 326 | |
| 327 // Insert the link text into the string at the appropriate offset. | |
| 328 scoped_nsobject<NSAttributedString> attributedString( | |
| 329 [[NSAttributedString alloc] initWithString:link | |
| 330 attributes:linkAttributes]); | |
| 331 [infoText.get() insertAttributedString:attributedString.get() | |
| 332 atIndex:linkOffset]; | |
| 333 // Update the label view with the new text. | |
| 334 [[label_.get() textStorage] setAttributedString:infoText]; | |
| 335 } | |
| 336 | |
| 337 @end | |
| 338 | |
| 339 | |
| 340 ///////////////////////////////////////////////////////////////////////// | |
| 341 // AlertInfoBarController implementation | |
| 342 | |
| 343 @implementation AlertInfoBarController | |
| 344 | |
| 345 // Alert infobars have a text message. | |
| 346 - (void)addAdditionalControls { | |
| 347 // No buttons. | |
| 348 [self removeButtons]; | |
| 349 | |
| 350 // Insert the text. | |
| 351 AlertInfoBarDelegate* delegate = delegate_->AsAlertInfoBarDelegate(); | |
| 352 DCHECK(delegate); | |
| 353 [self setLabelToMessage:base::SysUTF16ToNSString(delegate->GetMessageText())]; | |
| 354 } | |
| 355 | |
| 356 @end | |
| 357 | |
| 358 | |
| 359 ///////////////////////////////////////////////////////////////////////// | |
| 360 // LinkInfoBarController implementation | |
| 361 | |
| 362 @implementation LinkInfoBarController | |
| 363 | |
| 364 // Link infobars have a text message, of which part is linkified. We | |
| 365 // use an NSAttributedString to display styled text, and we set a | |
| 366 // NSLink attribute on the hyperlink portion of the message. Infobars | |
| 367 // use a custom NSTextField subclass, which allows us to override | |
| 368 // textView:clickedOnLink:atIndex: and intercept clicks. | |
| 369 // | |
| 370 - (void)addAdditionalControls { | |
| 371 // No buttons. | |
| 372 [self removeButtons]; | |
| 373 | |
| 374 LinkInfoBarDelegate* delegate = delegate_->AsLinkInfoBarDelegate(); | |
| 375 DCHECK(delegate); | |
| 376 size_t offset = std::wstring::npos; | |
| 377 string16 message = delegate->GetMessageTextWithOffset(&offset); | |
| 378 [self setLabelToMessage:base::SysUTF16ToNSString(message) | |
| 379 withLink:base::SysUTF16ToNSString(delegate->GetLinkText()) | |
| 380 atOffset:offset]; | |
| 381 } | |
| 382 | |
| 383 // Called when someone clicks on the link in the infobar. This method | |
| 384 // is called by the InfobarTextField on its delegate (the | |
| 385 // LinkInfoBarController). | |
| 386 - (void)linkClicked { | |
| 387 WindowOpenDisposition disposition = | |
| 388 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); | |
| 389 if (delegate_ && delegate_->AsLinkInfoBarDelegate()->LinkClicked(disposition)) | |
| 390 [self removeInfoBar]; | |
| 391 } | |
| 392 | |
| 393 @end | |
| 394 | |
| 395 | |
| 396 ///////////////////////////////////////////////////////////////////////// | |
| 397 // ConfirmInfoBarController implementation | |
| 398 | |
| 399 @implementation ConfirmInfoBarController | |
| 400 | |
| 401 // Called when someone clicks on the "OK" button. | |
| 402 - (IBAction)ok:(id)sender { | |
| 403 if (delegate_ && delegate_->AsConfirmInfoBarDelegate()->Accept()) | |
| 404 [self removeInfoBar]; | |
| 405 } | |
| 406 | |
| 407 // Called when someone clicks on the "Cancel" button. | |
| 408 - (IBAction)cancel:(id)sender { | |
| 409 if (delegate_ && delegate_->AsConfirmInfoBarDelegate()->Cancel()) | |
| 410 [self removeInfoBar]; | |
| 411 } | |
| 412 | |
| 413 // Confirm infobars can have OK and/or cancel buttons, depending on | |
| 414 // the return value of GetButtons(). We create each button if | |
| 415 // required and position them to the left of the close button. | |
| 416 - (void)addAdditionalControls { | |
| 417 ConfirmInfoBarDelegate* delegate = delegate_->AsConfirmInfoBarDelegate(); | |
| 418 DCHECK(delegate); | |
| 419 int visibleButtons = delegate->GetButtons(); | |
| 420 | |
| 421 NSRect okButtonFrame = [okButton_ frame]; | |
| 422 NSRect cancelButtonFrame = [cancelButton_ frame]; | |
| 423 | |
| 424 DCHECK(NSMaxX(okButtonFrame) < NSMinX(cancelButtonFrame)) | |
| 425 << "Cancel button expected to be on the right of the Ok button in nib"; | |
| 426 | |
| 427 CGFloat rightEdge = NSMaxX(cancelButtonFrame); | |
| 428 CGFloat spaceBetweenButtons = | |
| 429 NSMinX(cancelButtonFrame) - NSMaxX(okButtonFrame); | |
| 430 CGFloat spaceBeforeButtons = | |
| 431 NSMinX(okButtonFrame) - NSMaxX([label_.get() frame]); | |
| 432 | |
| 433 // Update and position the Cancel button if needed. Otherwise, hide it. | |
| 434 if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) { | |
| 435 [cancelButton_ setTitle:base::SysUTF16ToNSString( | |
| 436 delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL))]; | |
| 437 [GTMUILocalizerAndLayoutTweaker sizeToFitView:cancelButton_]; | |
| 438 cancelButtonFrame = [cancelButton_ frame]; | |
| 439 | |
| 440 // Position the cancel button to the left of the Close button. | |
| 441 cancelButtonFrame.origin.x = rightEdge - cancelButtonFrame.size.width; | |
| 442 [cancelButton_ setFrame:cancelButtonFrame]; | |
| 443 | |
| 444 // Update the rightEdge | |
| 445 rightEdge = NSMinX(cancelButtonFrame); | |
| 446 } else { | |
| 447 [cancelButton_ removeFromSuperview]; | |
| 448 } | |
| 449 | |
| 450 // Update and position the OK button if needed. Otherwise, hide it. | |
| 451 if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK) { | |
| 452 [okButton_ setTitle:base::SysUTF16ToNSString( | |
| 453 delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK))]; | |
| 454 [GTMUILocalizerAndLayoutTweaker sizeToFitView:okButton_]; | |
| 455 okButtonFrame = [okButton_ frame]; | |
| 456 | |
| 457 // If we had a Cancel button, leave space between the buttons. | |
| 458 if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) { | |
| 459 rightEdge -= spaceBetweenButtons; | |
| 460 } | |
| 461 | |
| 462 // Position the OK button on our current right edge. | |
| 463 okButtonFrame.origin.x = rightEdge - okButtonFrame.size.width; | |
| 464 [okButton_ setFrame:okButtonFrame]; | |
| 465 | |
| 466 | |
| 467 // Update the rightEdge | |
| 468 rightEdge = NSMinX(okButtonFrame); | |
| 469 } else { | |
| 470 [okButton_ removeFromSuperview]; | |
| 471 } | |
| 472 | |
| 473 // If we had either button, leave space before the edge of the textfield. | |
| 474 if ((visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) || | |
| 475 (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK)) { | |
| 476 rightEdge -= spaceBeforeButtons; | |
| 477 } | |
| 478 | |
| 479 NSRect frame = [label_.get() frame]; | |
| 480 DCHECK(rightEdge > NSMinX(frame)) | |
| 481 << "Need to make the xib larger to handle buttons with text this long"; | |
| 482 frame.size.width = rightEdge - NSMinX(frame); | |
| 483 [label_.get() setFrame:frame]; | |
| 484 | |
| 485 // Set the text and link. | |
| 486 NSString* message = base::SysUTF16ToNSString(delegate->GetMessageText()); | |
| 487 string16 link = delegate->GetLinkText(); | |
| 488 if (link.empty()) { | |
| 489 // Simple case: no link, so just set the message directly. | |
| 490 [self setLabelToMessage:message]; | |
| 491 } else { | |
| 492 // Inserting the link unintentionally causes the text to have a slightly | |
| 493 // different result to the simple case above: text is truncated on word | |
| 494 // boundaries (if needed) rather than elided with ellipses. | |
| 495 | |
| 496 // Add spacing between the label and the link. | |
| 497 message = [message stringByAppendingString:@" "]; | |
| 498 [self setLabelToMessage:message | |
| 499 withLink:base::SysUTF16ToNSString(link) | |
| 500 atOffset:[message length]]; | |
| 501 } | |
| 502 } | |
| 503 | |
| 504 // Called when someone clicks on the link in the infobar. This method | |
| 505 // is called by the InfobarTextField on its delegate (the | |
| 506 // LinkInfoBarController). | |
| 507 - (void)linkClicked { | |
| 508 WindowOpenDisposition disposition = | |
| 509 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); | |
| 510 if (delegate_ && | |
| 511 delegate_->AsConfirmInfoBarDelegate()->LinkClicked(disposition)) | |
| 512 [self removeInfoBar]; | |
| 513 } | |
| 514 | |
| 515 @end | |
| 516 | |
| 517 | |
| 518 ////////////////////////////////////////////////////////////////////////// | |
| 519 // CreateInfoBar() implementations | |
| 520 | |
| 521 InfoBar* AlertInfoBarDelegate::CreateInfoBar() { | |
| 522 AlertInfoBarController* controller = | |
| 523 [[AlertInfoBarController alloc] initWithDelegate:this]; | |
| 524 return new InfoBar(controller); | |
| 525 } | |
| 526 | |
| 527 InfoBar* LinkInfoBarDelegate::CreateInfoBar() { | |
| 528 LinkInfoBarController* controller = | |
| 529 [[LinkInfoBarController alloc] initWithDelegate:this]; | |
| 530 return new InfoBar(controller); | |
| 531 } | |
| 532 | |
| 533 InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() { | |
| 534 ConfirmInfoBarController* controller = | |
| 535 [[ConfirmInfoBarController alloc] initWithDelegate:this]; | |
| 536 return new InfoBar(controller); | |
| 537 } | |
| OLD | NEW |