Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / infobars / infobar_container_controller.mm
blob8caa878b04da223106bb6af90bd03f70759b140f
1 // Copyright (c) 2011 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.
5 #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
7 #include "base/logging.h"
8 #include "chrome/browser/infobars/infobar_service.h"
9 #import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h"
10 #import "chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.h"
11 #import "chrome/browser/ui/cocoa/infobars/infobar_controller.h"
12 #import "chrome/browser/ui/cocoa/view_id_util.h"
13 #include "components/infobars/core/confirm_infobar_delegate.h"
14 #include "components/infobars/core/infobar.h"
15 #include "components/infobars/core/infobar_container.h"
17 @interface InfoBarContainerController ()
18 // Removes |controller| from the list of controllers in this container and
19 // removes its view from the view hierarchy.  This method is safe to call while
20 // |controller| is still on the call stack.
21 - (void)removeController:(InfoBarController*)controller;
22 @end
25 @implementation InfoBarContainerController
27 @synthesize shouldSuppressTopInfoBarTip = shouldSuppressTopInfoBarTip_;
28 @synthesize infobarArrowX = infobarArrowX_;
30 - (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate {
31   DCHECK(resizeDelegate);
32   if ((self = [super initWithNibName:nil bundle:nil])) {
33     // This view and its subviews use autoresizing masks, The starting frame
34     // needs to be reasonably large, although its exactly values don't matter.
35     // It cannot be NSZeroRect.
36     base::scoped_nsobject<NSView> view(
37         [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 800, 100)]);
38     [view setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
39     view_id_util::SetID(view, VIEW_ID_INFO_BAR_CONTAINER);
40     [self setView:view];
42     resizeDelegate_ = resizeDelegate;
43     containerCocoa_.reset(new InfoBarContainerCocoa(self));
44     infobarControllers_.reset([[NSMutableArray alloc] init]);
45   }
46   return self;
49 - (void)dealloc {
50   // Delete the container so that any remaining infobars are removed.
51   containerCocoa_.reset();
52   DCHECK_EQ([infobarControllers_ count], 0U);
53   view_id_util::UnsetID([self view]);
54   [super dealloc];
57 - (void)changeWebContents:(content::WebContents*)contents {
58   currentWebContents_ = contents;
59   InfoBarService* infobar_service =
60       contents ? InfoBarService::FromWebContents(contents) : NULL;
61   containerCocoa_->ChangeInfoBarManager(infobar_service);
64 - (void)tabDetachedWithContents:(content::WebContents*)contents {
65   if (currentWebContents_ == contents)
66     [self changeWebContents:NULL];
69 - (CGFloat)overlappingTipHeight {
70   return containerCocoa_->GetVerticalOverlap(NULL);
73 - (void)addInfoBar:(InfoBarCocoa*)infobar
74           position:(NSUInteger)position {
75   InfoBarController* controller = infobar->controller();
76   [controller setContainerController:self];
77   [infobarControllers_ insertObject:controller atIndex:position];
79   NSView* relativeView = nil;
80   if (position > 0)
81     relativeView = [[infobarControllers_ objectAtIndex:position - 1] view];
82   [[self view] addSubview:[controller view]
83                positioned:NSWindowAbove
84                relativeTo:relativeView];
87 - (void)removeInfoBar:(InfoBarCocoa*)infobar {
88   [infobar->controller() infobarWillHide];
89   [self removeController:infobar->controller()];
92 - (void)positionInfoBarsAndRedraw:(BOOL)isAnimating {
93   if (isAnimating_ != isAnimating) {
94     isAnimating_ = isAnimating;
95     if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
96       [resizeDelegate_ setAnimationInProgress:isAnimating_];
97   }
99   NSRect containerBounds = [[self view] bounds];
100   int minY = 0;
102   // Stack the infobars at the bottom of the view, starting with the
103   // last infobar and working our way to the front of the array.  This
104   // way we ensure that the first infobar added shows up on top, with
105   // the others below.
106   for (InfoBarController* controller in
107            [infobarControllers_ reverseObjectEnumerator]) {
108     NSRect frame;
109     frame.origin.x = NSMinX(containerBounds);
110     frame.origin.y = minY;
111     frame.size.width = NSWidth(containerBounds);
112     frame.size.height = [controller infobar]->total_height();
113     [[controller view] setFrame:frame];
115     minY += NSHeight(frame) - [controller infobar]->arrow_height();
116     [controller layoutArrow];
117   }
119   [resizeDelegate_ resizeView:[self view] newHeight:[self heightOfInfoBars]];
122 - (void)setShouldSuppressTopInfoBarTip:(BOOL)flag {
123   if (shouldSuppressTopInfoBarTip_ == flag)
124     return;
125   shouldSuppressTopInfoBarTip_ = flag;
126   [self positionInfoBarsAndRedraw:isAnimating_];
129 - (void)removeController:(InfoBarController*)controller {
130   if (![infobarControllers_ containsObject:controller])
131     return;
133   // This code can be executed while InfoBarController is still on the stack, so
134   // we retain and autorelease the controller to prevent it from being
135   // dealloc'ed too early.
136   [[controller retain] autorelease];
137   [[controller view] removeFromSuperview];
138   [infobarControllers_ removeObject:controller];
141 - (void)setMaxTopArrowHeight:(NSInteger)height {
142   containerCocoa_->SetMaxTopArrowHeight(height, containerCocoa_.get());
145 - (CGFloat)heightOfInfoBars {
146   CGFloat totalHeight = 0;
147   for (InfoBarController* controller in infobarControllers_.get()) {
148     totalHeight += [controller infobar]->total_height() -
149                    [controller infobar]->arrow_height();
150   }
151   return totalHeight;
154 @end