Index: chrome/browser/cocoa/infobar_container_controller.mm |
=================================================================== |
--- chrome/browser/cocoa/infobar_container_controller.mm (revision 0) |
+++ chrome/browser/cocoa/infobar_container_controller.mm (revision 0) |
@@ -0,0 +1,191 @@ |
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/logging.h" |
+#include "base/mac_util.h" |
+#import "chrome/browser/cocoa/browser_window_controller.h" |
+#include "chrome/browser/cocoa/infobar.h" |
+#import "chrome/browser/cocoa/infobar_container_controller.h" |
+#import "chrome/browser/cocoa/infobar_controller.h" |
+#include "chrome/browser/cocoa/tab_strip_model_observer_bridge.h" |
+#include "chrome/browser/tab_contents/tab_contents.h" |
+#include "chrome/common/notification_service.h" |
+#include "skia/ext/skia_utils_mac.h" |
+ |
+// C++ class that receives INFOBAR_ADDED and INFOBAR_REMOVED |
+// notifications and proxies them back to |controller|. |
+class InfoBarNotificationObserver : public NotificationObserver { |
+ public: |
+ InfoBarNotificationObserver(InfoBarContainerController* controller) |
+ : controller_(controller) { |
+ } |
+ |
+ private: |
+ // NotificationObserver implementation |
+ void Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details) { |
+ switch (type.value) { |
+ case NotificationType::TAB_CONTENTS_INFOBAR_ADDED: |
+ [controller_ addInfoBar:Details<InfoBarDelegate>(details).ptr()]; |
+ break; |
+ case NotificationType::TAB_CONTENTS_INFOBAR_REMOVED: |
+ [controller_ |
+ removeInfoBarsForDelegate:Details<InfoBarDelegate>(details).ptr()]; |
+ break; |
+ default: |
+ NOTREACHED(); // we don't ask for anything else! |
+ break; |
+ } |
+ |
+ [controller_ positionInfoBarsAndRedraw]; |
+ } |
+ |
+ InfoBarContainerController* controller_; // weak, owns us. |
+}; |
+ |
+ |
+@interface InfoBarContainerController (PrivateMethods) |
+// Returns the desired height of the container view, computed by |
+// adding together the heights of all its subviews. |
+- (float)desiredHeight; |
+ |
+// Modifies this container to display infobars for the given |
+// |contents|. Registers for INFOBAR_ADDED and INFOBAR_REMOVED |
+// notifications for |contents|. If we are currently showing any |
+// infobars, removes them first and deregisters for any |
+// notifications. |contents| can be NULL, in which case no infobars |
+// are shown and no notifications are registered for. |
+- (void)changeTabContents:(TabContents*)contents; |
+ |
+@end |
+ |
+ |
+@implementation InfoBarContainerController |
+- (id)initWithTabStripModel:(TabStripModel*)model |
+ browserWindowController:(BrowserWindowController*)controller { |
+ DCHECK(controller); |
+ if ((self = [super initWithNibName:@"InfoBarContainer" |
+ bundle:mac_util::MainAppBundle()])) { |
+ browserController_ = controller; |
+ tabObserver_.reset(new TabStripModelObserverBridge(model, self)); |
+ infoBarObserver_.reset(new InfoBarNotificationObserver(self)); |
+ |
+ // NSMutableArray needs an initial capacity, and we rarely ever see |
+ // more than two infobars at a time, so that seems like a good choice. |
+ infobarControllers_.reset([[NSMutableArray alloc] initWithCapacity:2]); |
+ } |
+ return self; |
+} |
+ |
+- (void)dealloc { |
+ DCHECK([infobarControllers_ count] == 0); |
+ [super dealloc]; |
+} |
+ |
+- (void)removeDelegate:(InfoBarDelegate*)delegate { |
+ DCHECK(currentTabContents_); |
+ currentTabContents_->RemoveInfoBar(delegate); |
+} |
+ |
+// TabStripModelObserverBridge notifications |
+- (void)selectTabWithContents:(TabContents*)newContents |
+ previousContents:(TabContents*)oldContents |
+ atIndex:(NSInteger)index |
+ userGesture:(bool)wasUserGesture { |
+ [self changeTabContents:newContents]; |
+} |
+ |
+- (void)tabDetachedWithContents:(TabContents*)contents |
+ atIndex:(NSInteger)index { |
+ [self changeTabContents:NULL]; |
+} |
+ |
+@end |
+ |
+@implementation InfoBarContainerController (PrivateMethods) |
+ |
+- (float)desiredHeight { |
+ float height = 0; |
+ |
+ for (InfoBarController* controller in infobarControllers_.get()) { |
+ height += [[controller view] frame].size.height; |
+ } |
+ |
+ return height; |
+} |
+ |
+- (void)changeTabContents:(TabContents*)contents { |
+ registrar_.RemoveAll(); |
+ [self removeAllInfoBars]; |
+ |
+ currentTabContents_ = contents; |
+ if (currentTabContents_) { |
+ for (int i = 0; i < currentTabContents_->infobar_delegate_count(); ++i) { |
+ [self addInfoBar:currentTabContents_->GetInfoBarDelegateAt(i)]; |
+ } |
+ |
+ Source<TabContents> source(currentTabContents_); |
+ registrar_.Add(infoBarObserver_.get(), |
+ NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source); |
+ registrar_.Add(infoBarObserver_.get(), |
+ NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source); |
+ } |
+ |
+ [self positionInfoBarsAndRedraw]; |
+} |
+ |
+- (void)addInfoBar:(InfoBarDelegate*)delegate { |
+ scoped_ptr<InfoBar> infobar(delegate->CreateInfoBar()); |
+ InfoBarController* controller = infobar->controller(); |
+ [controller setContainerController:self]; |
+ [[self view] addSubview:[controller view]]; |
+ [infobarControllers_ addObject:[controller autorelease]]; |
+} |
+ |
+- (void)removeInfoBarsForDelegate:(InfoBarDelegate*)delegate { |
+ for (InfoBarController* controller in |
+ [NSArray arrayWithArray:infobarControllers_.get()]) { |
+ if ([controller delegate] == delegate) { |
+ // This code can be executed while -[InfoBarController closeInfoBar] is |
+ // still on the stack, so we retain and autorelease the controller to |
+ // prevent it from being dealloc'ed too early. |
+ [[controller retain] autorelease]; |
+ [[controller view] removeFromSuperview]; |
+ [infobarControllers_ removeObject:controller]; |
+ } |
+ } |
+} |
+ |
+- (void)removeAllInfoBars { |
+ for (InfoBarController* controller in infobarControllers_.get()) { |
+ [[controller view] removeFromSuperview]; |
+ } |
+ [infobarControllers_ removeAllObjects]; |
+} |
+ |
+- (void)positionInfoBarsAndRedraw { |
+ NSRect containerBounds = [[self view] bounds]; |
+ int minY = 0; |
+ |
+ // Stack the infobars at the bottom of the view, starting with the |
+ // last infobar and working our way to the front of the array. This |
+ // way we ensure that the first infobar added shows up on top, with |
+ // the others below. |
+ for (InfoBarController* controller in |
+ [infobarControllers_ reverseObjectEnumerator]) { |
+ NSView* view = [controller view]; |
+ NSRect frame = [view frame]; |
+ frame.origin.x = NSMinX(containerBounds); |
+ frame.size.width = NSWidth(containerBounds); |
+ frame.origin.y = minY; |
+ minY += frame.size.height; |
+ // TODO(rohitrao, jrg): Replace with an animator. |
+ [view setFrame:frame]; |
+ } |
+ |
+ [browserController_ infoBarResized:[self desiredHeight]]; |
+} |
+ |
+@end |
Property changes on: chrome/browser/cocoa/infobar_container_controller.mm |
___________________________________________________________________ |
Name: svn:eol-style |
+ LF |