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