| 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 #include "base/logging.h" | |
| 6 #include "base/mac/mac_util.h" | |
| 7 #include "chrome/browser/tab_contents/infobar_delegate.h" | |
| 8 #include "chrome/browser/tab_contents/tab_contents.h" | |
| 9 #import "chrome/browser/ui/cocoa/animatable_view.h" | |
| 10 #include "chrome/browser/ui/cocoa/infobar.h" | |
| 11 #import "chrome/browser/ui/cocoa/infobar_container_controller.h" | |
| 12 #import "chrome/browser/ui/cocoa/infobar_controller.h" | |
| 13 #import "chrome/browser/ui/cocoa/view_id_util.h" | |
| 14 #include "chrome/common/notification_details.h" | |
| 15 #include "chrome/common/notification_source.h" | |
| 16 #include "skia/ext/skia_utils_mac.h" | |
| 17 | |
| 18 // C++ class that receives INFOBAR_ADDED and INFOBAR_REMOVED | |
| 19 // notifications and proxies them back to |controller|. | |
| 20 class InfoBarNotificationObserver : public NotificationObserver { | |
| 21 public: | |
| 22 InfoBarNotificationObserver(InfoBarContainerController* controller) | |
| 23 : controller_(controller) { | |
| 24 } | |
| 25 | |
| 26 private: | |
| 27 // NotificationObserver implementation | |
| 28 void Observe(NotificationType type, | |
| 29 const NotificationSource& source, | |
| 30 const NotificationDetails& details) { | |
| 31 switch (type.value) { | |
| 32 case NotificationType::TAB_CONTENTS_INFOBAR_ADDED: | |
| 33 [controller_ addInfoBar:Details<InfoBarDelegate>(details).ptr() | |
| 34 animate:YES]; | |
| 35 break; | |
| 36 case NotificationType::TAB_CONTENTS_INFOBAR_REMOVED: | |
| 37 [controller_ | |
| 38 closeInfoBarsForDelegate:Details<InfoBarDelegate>(details).ptr() | |
| 39 animate:YES]; | |
| 40 break; | |
| 41 case NotificationType::TAB_CONTENTS_INFOBAR_REPLACED: { | |
| 42 typedef std::pair<InfoBarDelegate*, InfoBarDelegate*> | |
| 43 InfoBarDelegatePair; | |
| 44 InfoBarDelegatePair* delegates = | |
| 45 Details<InfoBarDelegatePair>(details).ptr(); | |
| 46 [controller_ | |
| 47 replaceInfoBarsForDelegate:delegates->first with:delegates->second]; | |
| 48 break; | |
| 49 } | |
| 50 default: | |
| 51 NOTREACHED(); // we don't ask for anything else! | |
| 52 break; | |
| 53 } | |
| 54 | |
| 55 [controller_ positionInfoBarsAndRedraw]; | |
| 56 } | |
| 57 | |
| 58 InfoBarContainerController* controller_; // weak, owns us. | |
| 59 }; | |
| 60 | |
| 61 | |
| 62 @interface InfoBarContainerController (PrivateMethods) | |
| 63 // Returns the desired height of the container view, computed by | |
| 64 // adding together the heights of all its subviews. | |
| 65 - (CGFloat)desiredHeight; | |
| 66 | |
| 67 @end | |
| 68 | |
| 69 | |
| 70 @implementation InfoBarContainerController | |
| 71 - (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate { | |
| 72 DCHECK(resizeDelegate); | |
| 73 if ((self = [super initWithNibName:@"InfoBarContainer" | |
| 74 bundle:base::mac::MainAppBundle()])) { | |
| 75 resizeDelegate_ = resizeDelegate; | |
| 76 infoBarObserver_.reset(new InfoBarNotificationObserver(self)); | |
| 77 | |
| 78 // NSMutableArray needs an initial capacity, and we rarely ever see | |
| 79 // more than two infobars at a time, so that seems like a good choice. | |
| 80 infobarControllers_.reset([[NSMutableArray alloc] initWithCapacity:2]); | |
| 81 } | |
| 82 return self; | |
| 83 } | |
| 84 | |
| 85 - (void)dealloc { | |
| 86 DCHECK([infobarControllers_ count] == 0); | |
| 87 view_id_util::UnsetID([self view]); | |
| 88 [super dealloc]; | |
| 89 } | |
| 90 | |
| 91 - (void)awakeFromNib { | |
| 92 // The info bar container view is an ordinary NSView object, so we set its | |
| 93 // ViewID here. | |
| 94 view_id_util::SetID([self view], VIEW_ID_INFO_BAR_CONTAINER); | |
| 95 } | |
| 96 | |
| 97 - (void)removeDelegate:(InfoBarDelegate*)delegate { | |
| 98 DCHECK(currentTabContents_); | |
| 99 currentTabContents_->RemoveInfoBar(delegate); | |
| 100 } | |
| 101 | |
| 102 - (void)removeController:(InfoBarController*)controller { | |
| 103 if (![infobarControllers_ containsObject:controller]) | |
| 104 return; | |
| 105 | |
| 106 // This code can be executed while InfoBarController is still on the stack, so | |
| 107 // we retain and autorelease the controller to prevent it from being | |
| 108 // dealloc'ed too early. | |
| 109 [[controller retain] autorelease]; | |
| 110 [[controller view] removeFromSuperview]; | |
| 111 [infobarControllers_ removeObject:controller]; | |
| 112 [self positionInfoBarsAndRedraw]; | |
| 113 } | |
| 114 | |
| 115 - (void)changeTabContents:(TabContents*)contents { | |
| 116 registrar_.RemoveAll(); | |
| 117 [self removeAllInfoBars]; | |
| 118 | |
| 119 currentTabContents_ = contents; | |
| 120 if (currentTabContents_) { | |
| 121 for (int i = 0; i < currentTabContents_->infobar_delegate_count(); ++i) { | |
| 122 [self addInfoBar:currentTabContents_->GetInfoBarDelegateAt(i) | |
| 123 animate:NO]; | |
| 124 } | |
| 125 | |
| 126 Source<TabContents> source(currentTabContents_); | |
| 127 registrar_.Add(infoBarObserver_.get(), | |
| 128 NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source); | |
| 129 registrar_.Add(infoBarObserver_.get(), | |
| 130 NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source); | |
| 131 registrar_.Add(infoBarObserver_.get(), | |
| 132 NotificationType::TAB_CONTENTS_INFOBAR_REPLACED, source); | |
| 133 } | |
| 134 | |
| 135 [self positionInfoBarsAndRedraw]; | |
| 136 } | |
| 137 | |
| 138 - (void)tabDetachedWithContents:(TabContents*)contents { | |
| 139 if (currentTabContents_ == contents) | |
| 140 [self changeTabContents:NULL]; | |
| 141 } | |
| 142 | |
| 143 - (void)resizeView:(NSView*)view newHeight:(CGFloat)height { | |
| 144 NSRect frame = [view frame]; | |
| 145 frame.size.height = height; | |
| 146 [view setFrame:frame]; | |
| 147 [self positionInfoBarsAndRedraw]; | |
| 148 } | |
| 149 | |
| 150 - (void)setAnimationInProgress:(BOOL)inProgress { | |
| 151 if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)]) | |
| 152 [resizeDelegate_ setAnimationInProgress:inProgress]; | |
| 153 } | |
| 154 | |
| 155 @end | |
| 156 | |
| 157 @implementation InfoBarContainerController (PrivateMethods) | |
| 158 | |
| 159 - (CGFloat)desiredHeight { | |
| 160 CGFloat height = 0; | |
| 161 for (InfoBarController* controller in infobarControllers_.get()) | |
| 162 height += NSHeight([[controller view] frame]); | |
| 163 return height; | |
| 164 } | |
| 165 | |
| 166 - (void)addInfoBar:(InfoBarDelegate*)delegate animate:(BOOL)animate { | |
| 167 scoped_ptr<InfoBar> infobar(delegate->CreateInfoBar()); | |
| 168 InfoBarController* controller = infobar->controller(); | |
| 169 [controller setContainerController:self]; | |
| 170 [[controller animatableView] setResizeDelegate:self]; | |
| 171 [[self view] addSubview:[controller view]]; | |
| 172 [infobarControllers_ addObject:[controller autorelease]]; | |
| 173 | |
| 174 if (animate) | |
| 175 [controller animateOpen]; | |
| 176 else | |
| 177 [controller open]; | |
| 178 } | |
| 179 | |
| 180 - (void)closeInfoBarsForDelegate:(InfoBarDelegate*)delegate | |
| 181 animate:(BOOL)animate { | |
| 182 for (InfoBarController* controller in | |
| 183 [NSArray arrayWithArray:infobarControllers_.get()]) { | |
| 184 if ([controller delegate] == delegate) { | |
| 185 [controller infobarWillClose]; | |
| 186 if (animate) | |
| 187 [controller animateClosed]; | |
| 188 else | |
| 189 [controller close]; | |
| 190 } | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 - (void)replaceInfoBarsForDelegate:(InfoBarDelegate*)old_delegate | |
| 195 with:(InfoBarDelegate*)new_delegate { | |
| 196 [self closeInfoBarsForDelegate:old_delegate animate:NO]; | |
| 197 [self addInfoBar:new_delegate animate:NO]; | |
| 198 } | |
| 199 | |
| 200 - (void)removeAllInfoBars { | |
| 201 for (InfoBarController* controller in infobarControllers_.get()) { | |
| 202 [[controller animatableView] stopAnimation]; | |
| 203 [[controller view] removeFromSuperview]; | |
| 204 } | |
| 205 [infobarControllers_ removeAllObjects]; | |
| 206 } | |
| 207 | |
| 208 - (void)positionInfoBarsAndRedraw { | |
| 209 NSRect containerBounds = [[self view] bounds]; | |
| 210 int minY = 0; | |
| 211 | |
| 212 // Stack the infobars at the bottom of the view, starting with the | |
| 213 // last infobar and working our way to the front of the array. This | |
| 214 // way we ensure that the first infobar added shows up on top, with | |
| 215 // the others below. | |
| 216 for (InfoBarController* controller in | |
| 217 [infobarControllers_ reverseObjectEnumerator]) { | |
| 218 NSView* view = [controller view]; | |
| 219 NSRect frame = [view frame]; | |
| 220 frame.origin.x = NSMinX(containerBounds); | |
| 221 frame.size.width = NSWidth(containerBounds); | |
| 222 frame.origin.y = minY; | |
| 223 minY += frame.size.height; | |
| 224 [view setFrame:frame]; | |
| 225 } | |
| 226 | |
| 227 [resizeDelegate_ resizeView:[self view] newHeight:[self desiredHeight]]; | |
| 228 } | |
| 229 | |
| 230 @end | |
| OLD | NEW |