1 // Copyright (c) 2012 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/infobars/infobar_controller.h" 6 7 #include "base/logging.h" 8 #include "base/mac/bundle_locations.h" 9 #include "base/mac/mac_util.h" 10 #include "chrome/browser/infobars/infobar_service.h" 11 #import "chrome/browser/ui/cocoa/animatable_view.h" 12 #import "chrome/browser/ui/cocoa/browser_window_controller.h" 13 #import "chrome/browser/ui/cocoa/image_button_cell.h" 14 #include "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" 15 #import "chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.h" 16 #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" 17 #import "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h" 18 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" 19 #include "grit/theme_resources.h" 20 #import "ui/base/cocoa/controls/hyperlink_text_view.h" 21 #include "ui/gfx/image/image.h" 22 #include "ui/resources/grit/ui_resources.h" 23 24 @interface InfoBarController () 25 // Sets |label_| based on |labelPlaceholder_|, sets |labelPlaceholder_| to nil. 26 - (void)initializeLabel; 27 @end 28 29 @implementation InfoBarController 30 31 @synthesize containerController = containerController_; 32 33 - (id)initWithInfoBar:(InfoBarCocoa*)infobar { 34 if ((self = [super initWithNibName:@"InfoBar" 35 bundle:base::mac::FrameworkBundle()])) { 36 DCHECK(infobar); 37 infobar_ = infobar->GetWeakPtr(); 38 } 39 return self; 40 } 41 42 // All infobars have an icon, so we set up the icon in the base class 43 // awakeFromNib. 44 - (void)awakeFromNib { 45 [[closeButton_ cell] setImageID:IDR_CLOSE_1 46 forButtonState:image_button_cell::kDefaultState]; 47 [[closeButton_ cell] setImageID:IDR_CLOSE_1_H 48 forButtonState:image_button_cell::kHoverState]; 49 [[closeButton_ cell] setImageID:IDR_CLOSE_1_P 50 forButtonState:image_button_cell::kPressedState]; 51 [[closeButton_ cell] setImageID:IDR_CLOSE_1 52 forButtonState:image_button_cell::kDisabledState]; 53 54 if (![self delegate]->GetIcon().IsEmpty()) { 55 [image_ setImage:[self delegate]->GetIcon().ToNSImage()]; 56 } else { 57 // No icon, remove it from the view and grow the textfield to include the 58 // space. 59 NSRect imageFrame = [image_ frame]; 60 NSRect labelFrame = [labelPlaceholder_ frame]; 61 labelFrame.size.width += NSMinX(imageFrame) - NSMinX(labelFrame); 62 labelFrame.origin.x = imageFrame.origin.x; 63 [image_ removeFromSuperview]; 64 image_ = nil; 65 [labelPlaceholder_ setFrame:labelFrame]; 66 } 67 [self initializeLabel]; 68 69 [self addAdditionalControls]; 70 71 [infoBarView_ setInfobarType:[self delegate]->GetInfoBarType()]; 72 [infoBarView_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 73 } 74 75 - (void)dealloc { 76 [okButton_ setTarget:nil]; 77 [cancelButton_ setTarget:nil]; 78 [closeButton_ setTarget:nil]; 79 [super dealloc]; 80 } 81 82 - (InfoBarCocoa*)infobar { 83 return infobar_.get(); 84 } 85 86 // Called when someone clicks on the embedded link. 87 - (BOOL)textView:(NSTextView*)textView 88 clickedOnLink:(id)link 89 atIndex:(NSUInteger)charIndex { 90 if ([self respondsToSelector:@selector(linkClicked)]) 91 [self performSelector:@selector(linkClicked)]; 92 return YES; 93 } 94 95 - (BOOL)isOwned { 96 return infobar_ && infobar_->OwnerCocoa() != NULL; 97 } 98 99 // Called when someone clicks on the ok button. 100 - (void)ok:(id)sender { 101 // Subclasses must override this method if they do not hide the ok button. 102 NOTREACHED(); 103 } 104 105 // Called when someone clicks on the cancel button. 106 - (void)cancel:(id)sender { 107 // Subclasses must override this method if they do not hide the cancel button. 108 NOTREACHED(); 109 } 110 111 // Called when someone clicks on the close button. 112 - (void)dismiss:(id)sender { 113 if (![self isOwned]) 114 return; 115 [self delegate]->InfoBarDismissed(); 116 [self removeSelf]; 117 } 118 119 - (void)removeSelf { 120 infobar_->RemoveSelf(); 121 } 122 123 - (void)addAdditionalControls { 124 // Default implementation does nothing. 125 } 126 127 - (void)infobarWillHide { 128 } 129 130 - (void)infobarWillClose { 131 } 132 133 - (void)removeButtons { 134 // Extend the label all the way across. 135 NSRect labelFrame = [label_.get() frame]; 136 labelFrame.size.width = NSMaxX([cancelButton_ frame]) - NSMinX(labelFrame); 137 [okButton_ removeFromSuperview]; 138 okButton_ = nil; 139 [cancelButton_ removeFromSuperview]; 140 cancelButton_ = nil; 141 [label_.get() setFrame:labelFrame]; 142 } 143 144 - (void)layoutArrow { 145 [infoBarView_ setArrowHeight:infobar_->arrow_height()]; 146 [infoBarView_ setArrowHalfWidth:infobar_->arrow_half_width()]; 147 [infoBarView_ setHasTip:![containerController_ shouldSuppressTopInfoBarTip]]; 148 149 // Convert from window to view coordinates. 150 NSPoint point = NSMakePoint([containerController_ infobarArrowX], 0); 151 point = [infoBarView_ convertPoint:point fromView:nil]; 152 [infoBarView_ setArrowX:point.x]; 153 } 154 155 - (void)disablePopUpMenu:(NSMenu*)menu { 156 // If the menu is re-opened, prevent queries to update items. 157 [menu setDelegate:nil]; 158 159 // Prevent target/action messages to the controller. 160 for (NSMenuItem* item in [menu itemArray]) { 161 [item setEnabled:NO]; 162 [item setTarget:nil]; 163 } 164 } 165 166 - (infobars::InfoBarDelegate*)delegate { 167 return infobar_->delegate(); 168 } 169 170 - (void)initializeLabel { 171 // Replace the label placeholder NSTextField with the real label NSTextView. 172 // The former doesn't show links in a nice way, but the latter can't be added 173 // in IB without a containing scroll view, so create the NSTextView 174 // programmatically. 175 base::scoped_nsobject<HyperlinkTextView> newLabel( 176 [[HyperlinkTextView alloc] initWithFrame:[labelPlaceholder_ frame]]); 177 [newLabel setDrawsBackgroundUsingSuperview:YES]; 178 [newLabel setAutoresizingMask:[labelPlaceholder_ autoresizingMask]]; 179 [[labelPlaceholder_ superview] 180 replaceSubview:labelPlaceholder_ with:newLabel]; 181 labelPlaceholder_ = nil; // Now released. 182 [newLabel setDelegate:self]; 183 184 label_.reset(newLabel.release()); 185 } 186 187 @end 188