Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: chrome/browser/ui/cocoa/infobars/infobar_controller.mm

Issue 23338005: Mac InfoBar: Use cross platform infobar classes (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "chrome/browser/ui/cocoa/infobars/infobar_controller.h" 5 #import "chrome/browser/ui/cocoa/infobars/infobar_controller.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/mac/bundle_locations.h" 8 #include "base/mac/bundle_locations.h"
9 #include "base/mac/mac_util.h" 9 #include "base/mac/mac_util.h"
10 #include "chrome/browser/infobars/infobar_service.h" 10 #include "chrome/browser/infobars/infobar_service.h"
11 #import "chrome/browser/ui/cocoa/animatable_view.h" 11 #import "chrome/browser/ui/cocoa/animatable_view.h"
12 #import "chrome/browser/ui/cocoa/browser_window_controller.h" 12 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
13 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h" 13 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
14 #import "chrome/browser/ui/cocoa/image_button_cell.h" 14 #import "chrome/browser/ui/cocoa/image_button_cell.h"
15 #include "chrome/browser/ui/cocoa/infobars/infobar.h" 15 #include "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h"
16 #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_container_controller.h"
17 #import "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h" 18 #import "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h"
18 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" 19 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
19 #include "grit/theme_resources.h" 20 #include "grit/theme_resources.h"
20 #include "grit/ui_resources.h" 21 #include "grit/ui_resources.h"
21 #include "ui/gfx/image/image.h" 22 #include "ui/gfx/image/image.h"
22 23
23 namespace { 24 @interface InfoBarController ()
24 // Durations set to match the default SlideAnimation duration.
25 const float kAnimateOpenDuration = 0.12;
26 const float kAnimateCloseDuration = 0.12;
27 }
28
29 @interface InfoBarController (PrivateMethods)
30 // Sets |label_| based on |labelPlaceholder_|, sets |labelPlaceholder_| to nil. 25 // Sets |label_| based on |labelPlaceholder_|, sets |labelPlaceholder_| to nil.
31 - (void)initializeLabel; 26 - (void)initializeLabel;
32
33 // Performs final cleanup after an animation is finished or stopped, including
34 // notifying the InfoBarDelegate that the infobar was closed and removing the
35 // infobar from its container, if necessary.
36 - (void)cleanUpAfterAnimation:(BOOL)finished;
37
38 // Returns the point, in window coordinates, at which the apex of the infobar
39 // tip should be drawn.
40 - (NSPoint)pointForTipApex;
41 @end 27 @end
42 28
43 @implementation InfoBarController 29 @implementation InfoBarController
44 30
45 @synthesize containerController = containerController_; 31 @synthesize containerController = containerController_;
46 @synthesize delegate = delegate_; 32 @synthesize infobar = infobar_;
47 33
48 - (id)initWithDelegate:(InfoBarDelegate*)delegate 34 - (id)initWithInfoBar:(InfoBarCocoa*)infobar {
49 owner:(InfoBarService*)owner {
50 DCHECK(delegate);
51 if ((self = [super initWithNibName:@"InfoBar" 35 if ((self = [super initWithNibName:@"InfoBar"
52 bundle:base::mac::FrameworkBundle()])) { 36 bundle:base::mac::FrameworkBundle()])) {
53 delegate_ = delegate; 37 DCHECK(infobar);
54 owner_ = owner; 38 infobar_ = infobar;
55 } 39 }
56 return self; 40 return self;
57 } 41 }
58 42
59 // All infobars have an icon, so we set up the icon in the base class 43 // All infobars have an icon, so we set up the icon in the base class
60 // awakeFromNib. 44 // awakeFromNib.
61 - (void)awakeFromNib { 45 - (void)awakeFromNib {
62 DCHECK(delegate_);
63
64 [[closeButton_ cell] setImageID:IDR_CLOSE_1 46 [[closeButton_ cell] setImageID:IDR_CLOSE_1
65 forButtonState:image_button_cell::kDefaultState]; 47 forButtonState:image_button_cell::kDefaultState];
66 [[closeButton_ cell] setImageID:IDR_CLOSE_1_H 48 [[closeButton_ cell] setImageID:IDR_CLOSE_1_H
67 forButtonState:image_button_cell::kHoverState]; 49 forButtonState:image_button_cell::kHoverState];
68 [[closeButton_ cell] setImageID:IDR_CLOSE_1_P 50 [[closeButton_ cell] setImageID:IDR_CLOSE_1_P
69 forButtonState:image_button_cell::kPressedState]; 51 forButtonState:image_button_cell::kPressedState];
70 [[closeButton_ cell] setImageID:IDR_CLOSE_1 52 [[closeButton_ cell] setImageID:IDR_CLOSE_1
71 forButtonState:image_button_cell::kDisabledState]; 53 forButtonState:image_button_cell::kDisabledState];
72 54
73 if (!delegate_->GetIcon().IsEmpty()) { 55 if (![self delegate]->GetIcon().IsEmpty()) {
74 [image_ setImage:delegate_->GetIcon().ToNSImage()]; 56 [image_ setImage:[self delegate]->GetIcon().ToNSImage()];
75 } else { 57 } else {
76 // No icon, remove it from the view and grow the textfield to include the 58 // No icon, remove it from the view and grow the textfield to include the
77 // space. 59 // space.
78 NSRect imageFrame = [image_ frame]; 60 NSRect imageFrame = [image_ frame];
79 NSRect labelFrame = [labelPlaceholder_ frame]; 61 NSRect labelFrame = [labelPlaceholder_ frame];
80 labelFrame.size.width += NSMinX(imageFrame) - NSMinX(labelFrame); 62 labelFrame.size.width += NSMinX(imageFrame) - NSMinX(labelFrame);
81 labelFrame.origin.x = imageFrame.origin.x; 63 labelFrame.origin.x = imageFrame.origin.x;
82 [image_ removeFromSuperview]; 64 [image_ removeFromSuperview];
83 image_ = nil; 65 image_ = nil;
84 [labelPlaceholder_ setFrame:labelFrame]; 66 [labelPlaceholder_ setFrame:labelFrame];
85 } 67 }
86 [self initializeLabel]; 68 [self initializeLabel];
87 69
88 [self addAdditionalControls]; 70 [self addAdditionalControls];
89 71
90 infoBarView_.tipApex = [self pointForTipApex]; 72 [infoBarView_ setInfobarType:[self delegate]->GetInfoBarType()];
91 [infoBarView_ setInfobarType:delegate_->GetInfoBarType()];
92 } 73 }
93 74
94 - (void)dealloc { 75 - (void)dealloc {
95 [okButton_ setTarget:nil]; 76 [okButton_ setTarget:nil];
96 [cancelButton_ setTarget:nil]; 77 [cancelButton_ setTarget:nil];
97 [closeButton_ setTarget:nil]; 78 [closeButton_ setTarget:nil];
98 [super dealloc]; 79 [super dealloc];
99 } 80 }
100 81
101 // Called when someone clicks on the embedded link. 82 // Called when someone clicks on the embedded link.
102 - (BOOL)textView:(NSTextView*)textView 83 - (BOOL)textView:(NSTextView*)textView
103 clickedOnLink:(id)link 84 clickedOnLink:(id)link
104 atIndex:(NSUInteger)charIndex { 85 atIndex:(NSUInteger)charIndex {
105 if ([self respondsToSelector:@selector(linkClicked)]) 86 if ([self respondsToSelector:@selector(linkClicked)])
106 [self performSelector:@selector(linkClicked)]; 87 [self performSelector:@selector(linkClicked)];
107 return YES; 88 return YES;
108 } 89 }
109 90
110 - (BOOL)isOwned { 91 - (BOOL)isOwned {
111 return !!owner_; 92 return infobar_->OwnerCocoa() != NULL;
112 } 93 }
113 94
114 // Called when someone clicks on the ok button. 95 // Called when someone clicks on the ok button.
115 - (void)ok:(id)sender { 96 - (void)ok:(id)sender {
116 // Subclasses must override this method if they do not hide the ok button. 97 // Subclasses must override this method if they do not hide the ok button.
117 NOTREACHED(); 98 NOTREACHED();
118 } 99 }
119 100
120 // Called when someone clicks on the cancel button. 101 // Called when someone clicks on the cancel button.
121 - (void)cancel:(id)sender { 102 - (void)cancel:(id)sender {
122 // Subclasses must override this method if they do not hide the cancel button. 103 // Subclasses must override this method if they do not hide the cancel button.
123 NOTREACHED(); 104 NOTREACHED();
124 } 105 }
125 106
126 // Called when someone clicks on the close button. 107 // Called when someone clicks on the close button.
127 - (void)dismiss:(id)sender { 108 - (void)dismiss:(id)sender {
128 if (![self isOwned]) 109 if (![self isOwned])
129 return; 110 return;
130 delegate_->InfoBarDismissed(); 111 [self delegate]->InfoBarDismissed();
131 [self removeSelf]; 112 [self removeSelf];
132 } 113 }
133 114
134 - (void)removeSelf { 115 - (void)removeSelf {
135 // |owner_| should never be NULL here. If it is, then someone violated what 116 infobar_->RemoveSelfCocoa();
136 // they were supposed to do -- e.g. a ConfirmInfoBarDelegate subclass returned
137 // true from Accept() or Cancel() even though the infobar was already closing.
138 // In the worst case, if we also switched tabs during that process, then
139 // |this| has already been destroyed. But if that's the case, then we're
140 // going to deref a garbage |this| pointer here whether we check |owner_| or
141 // not, and in other cases (where we're still closing and |this| is valid),
142 // checking |owner_| here will avoid a NULL deref.
143 if (owner_)
144 owner_->RemoveInfoBar(delegate_);
145 }
146
147 - (AnimatableView*)animatableView {
148 return static_cast<AnimatableView*>([self view]);
149 }
150
151 - (void)open {
152 // Simply reset the frame size to its opened size, forcing a relayout.
153 CGFloat finalHeight = [[self view] frame].size.height;
154 [[self animatableView] setHeight:finalHeight];
155 }
156
157 - (void)animateOpen {
158 // Force the frame size to be 0 and then start an animation.
159 NSRect frame = [[self view] frame];
160 CGFloat finalHeight = frame.size.height;
161 frame.size.height = 0;
162 [[self view] setFrame:frame];
163 [[self animatableView] animateToNewHeight:finalHeight
164 duration:kAnimateOpenDuration];
165 }
166
167 - (void)close {
168 // Stop any running animations.
169 [[self animatableView] stopAnimation];
170 infoBarClosing_ = YES;
171 [self cleanUpAfterAnimation:YES];
172 }
173
174 - (void)animateClosed {
175 // Notify the container of our intentions.
176 [containerController_ willRemoveController:self];
177
178 // Start animating closed. We will receive a notification when the animation
179 // is done, at which point we can remove our view from the hierarchy and
180 // notify the delegate that the infobar was closed.
181 [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration];
182
183 // The above call may trigger an animationDidStop: notification for any
184 // currently-running animations, so do not set |infoBarClosing_| until after
185 // starting the animation.
186 infoBarClosing_ = YES;
187 } 117 }
188 118
189 - (void)addAdditionalControls { 119 - (void)addAdditionalControls {
190 // Default implementation does nothing. 120 // Default implementation does nothing.
191 } 121 }
192 122
193 - (void)infobarWillClose { 123 - (void)infobarWillClose {
194 owner_ = NULL;
195 } 124 }
196 125
197 - (void)removeButtons { 126 - (void)removeButtons {
198 // Extend the label all the way across. 127 // Extend the label all the way across.
199 NSRect labelFrame = [label_.get() frame]; 128 NSRect labelFrame = [label_.get() frame];
200 labelFrame.size.width = NSMaxX([cancelButton_ frame]) - NSMinX(labelFrame); 129 labelFrame.size.width = NSMaxX([cancelButton_ frame]) - NSMinX(labelFrame);
201 [okButton_ removeFromSuperview]; 130 [okButton_ removeFromSuperview];
202 okButton_ = nil; 131 okButton_ = nil;
203 [cancelButton_ removeFromSuperview]; 132 [cancelButton_ removeFromSuperview];
204 cancelButton_ = nil; 133 cancelButton_ = nil;
205 [label_.get() setFrame:labelFrame]; 134 [label_.get() setFrame:labelFrame];
206 } 135 }
207 136
208 - (void)setHasTip:(BOOL)hasTip { 137 - (void)layoutArrow {
209 [infoBarView_ setHasTip:hasTip]; 138 [infoBarView_ setArrowHeight:infobar_->arrow_height()];
139 [infoBarView_ setArrowHalfWidth:infobar_->arrow_half_width()];
140 [infoBarView_ setHasTip:![containerController_ shouldSuppressTopInfoBarTip]];
141
142 // Convert from window to view coordinates.
143 NSPoint point = NSMakePoint([containerController_ infobarArrowX], 0);
144 point = [infoBarView_ convertPoint:point fromView:nil];
145 [infoBarView_ setArrowX:point.x];
210 } 146 }
211 147
212 - (void)disablePopUpMenu:(NSMenu*)menu { 148 - (void)disablePopUpMenu:(NSMenu*)menu {
213 // Remove the menu if visible. 149 // Remove the menu if visible.
214 [menu cancelTracking]; 150 [menu cancelTracking];
215 151
216 // If the menu is re-opened, prevent queries to update items. 152 // If the menu is re-opened, prevent queries to update items.
217 [menu setDelegate:nil]; 153 [menu setDelegate:nil];
218 154
219 // Prevent target/action messages to the controller. 155 // Prevent target/action messages to the controller.
220 for (NSMenuItem* item in [menu itemArray]) { 156 for (NSMenuItem* item in [menu itemArray]) {
221 [item setEnabled:NO]; 157 [item setEnabled:NO];
222 [item setTarget:nil]; 158 [item setTarget:nil];
223 } 159 }
224 } 160 }
225 161
226 @end 162 - (InfoBarDelegate*)delegate {
227 163 return infobar_->delegate();
228 @implementation InfoBarController (PrivateMethods) 164 }
229 165
230 - (void)initializeLabel { 166 - (void)initializeLabel {
231 // Replace the label placeholder NSTextField with the real label NSTextView. 167 // Replace the label placeholder NSTextField with the real label NSTextView.
232 // The former doesn't show links in a nice way, but the latter can't be added 168 // The former doesn't show links in a nice way, but the latter can't be added
233 // in IB without a containing scroll view, so create the NSTextView 169 // in IB without a containing scroll view, so create the NSTextView
234 // programmatically. 170 // programmatically.
235 label_.reset([[HyperlinkTextView alloc] 171 label_.reset([[HyperlinkTextView alloc]
236 initWithFrame:[labelPlaceholder_ frame]]); 172 initWithFrame:[labelPlaceholder_ frame]]);
237 [label_.get() setAutoresizingMask:[labelPlaceholder_ autoresizingMask]]; 173 [label_.get() setAutoresizingMask:[labelPlaceholder_ autoresizingMask]];
238 [[labelPlaceholder_ superview] 174 [[labelPlaceholder_ superview]
239 replaceSubview:labelPlaceholder_ with:label_.get()]; 175 replaceSubview:labelPlaceholder_ with:label_.get()];
240 labelPlaceholder_ = nil; // Now released. 176 labelPlaceholder_ = nil; // Now released.
241 [label_.get() setDelegate:self]; 177 [label_.get() setDelegate:self];
242 } 178 }
243 179
244 - (void)cleanUpAfterAnimation:(BOOL)finished {
245 // Don't need to do any cleanup if the bar was animating open.
246 if (!infoBarClosing_)
247 return;
248
249 if (delegate_) {
250 delete delegate_;
251 delegate_ = NULL;
252 }
253
254 // If the animation ran to completion, then we need to remove ourselves from
255 // the container. If the animation was interrupted, then the container will
256 // take care of removing us.
257 // TODO(rohitrao): UGH! This works for now, but should be cleaner.
258 if (finished)
259 [containerController_ removeController:self];
260 }
261
262 - (void)animationDidStop:(NSAnimation*)animation {
263 [self cleanUpAfterAnimation:NO];
264 }
265
266 - (void)animationDidEnd:(NSAnimation*)animation {
267 [self cleanUpAfterAnimation:YES];
268 }
269
270 - (NSPoint)pointForTipApex {
271 BrowserWindowController* windowController =
272 [containerController_ browserWindowController];
273 if (!windowController) {
274 // This should only happen in unit tests.
275 return NSZeroPoint;
276 }
277
278 LocationBarViewMac* locationBar = [windowController locationBarBridge];
279 return locationBar->GetPageInfoBubblePoint();
280 }
281
282 @end 180 @end
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/infobars/infobar_controller.h ('k') | chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698