diff options
author | sail@chromium.org <sail@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-28 07:52:44 +0000 |
---|---|---|
committer | sail@chromium.org <sail@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-28 07:52:44 +0000 |
commit | 86368aec2fb14d390cd056fe0b218b4f3f1c7643 (patch) | |
tree | b16803041ebecc0dfbd253bef5db56fa283611c8 | |
parent | 32f8b3e0daa9f2b82bfb4049a9a1e74e5f2d7275 (diff) | |
download | chromium_src-86368aec2fb14d390cd056fe0b218b4f3f1c7643.zip chromium_src-86368aec2fb14d390cd056fe0b218b4f3f1c7643.tar.gz chromium_src-86368aec2fb14d390cd056fe0b218b4f3f1c7643.tar.bz2 |
Mac InfoBar: Use cross platform infobar classes
Currently the Mac code has a dummy InfoBar implementation that it unused.
This code replaces that with the cross platform implementation.
Using the cross platform implementation means:
- animation is now driven by the cross platform code
- layout is now controlled by InfoBarContainer
- InfoBarDelegate is now owned by InfoBar
BUG=62154
TEST=
TBR=thakis
Review URL: https://chromiumcodereview.appspot.com/23338005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219956 0039d316-1c4b-4281-b951-d872f2087c98
31 files changed, 446 insertions, 857 deletions
diff --git a/chrome/app/nibs/InfoBarContainer.xib b/chrome/app/nibs/InfoBarContainer.xib deleted file mode 100644 index cdd5bbcd..0000000 --- a/chrome/app/nibs/InfoBarContainer.xib +++ /dev/null @@ -1,169 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10"> - <data> - <int key="IBDocument.SystemTarget">1050</int> - <string key="IBDocument.SystemVersion">12B19</string> - <string key="IBDocument.InterfaceBuilderVersion">2549</string> - <string key="IBDocument.AppKitVersion">1187</string> - <string key="IBDocument.HIToolboxVersion">624.00</string> - <object class="NSMutableDictionary" key="IBDocument.PluginVersions"> - <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="NS.object.0">2549</string> - </object> - <object class="NSArray" key="IBDocument.IntegratedClassDependencies"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>NSCustomObject</string> - <string>NSCustomView</string> - </object> - <object class="NSArray" key="IBDocument.PluginDependencies"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - </object> - <object class="NSMutableDictionary" key="IBDocument.Metadata"> - <string key="NS.key.0">PluginDependencyRecalculationVersion</string> - <integer value="1" key="NS.object.0"/> - </object> - <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSCustomObject" id="1001"> - <string key="NSClassName">InfoBarContainerController</string> - </object> - <object class="NSCustomObject" id="1003"> - <string key="NSClassName">FirstResponder</string> - </object> - <object class="NSCustomObject" id="1004"> - <string key="NSClassName">NSApplication</string> - </object> - <object class="NSCustomView" id="1005"> - <reference key="NSNextResponder"/> - <int key="NSvFlags">266</int> - <string key="NSFrameSize">{480, 0}</string> - <reference key="NSSuperview"/> - <reference key="NSWindow"/> - <string key="NSClassName">NSView</string> - </object> - </object> - <object class="IBObjectContainer" key="IBDocument.Objects"> - <object class="NSMutableArray" key="connectionRecords"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="IBConnectionRecord"> - <object class="IBOutletConnection" key="connection"> - <string key="label">view</string> - <reference key="source" ref="1001"/> - <reference key="destination" ref="1005"/> - </object> - <int key="connectionID">12</int> - </object> - </object> - <object class="IBMutableOrderedSet" key="objectRecords"> - <object class="NSArray" key="orderedObjects"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="IBObjectRecord"> - <int key="objectID">0</int> - <object class="NSArray" key="object" id="0"> - <bool key="EncodedWithXMLCoder">YES</bool> - </object> - <reference key="children" ref="1000"/> - <nil key="parent"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">-2</int> - <reference key="object" ref="1001"/> - <reference key="parent" ref="0"/> - <string key="objectName">File's Owner</string> - </object> - <object class="IBObjectRecord"> - <int key="objectID">-1</int> - <reference key="object" ref="1003"/> - <reference key="parent" ref="0"/> - <string key="objectName">First Responder</string> - </object> - <object class="IBObjectRecord"> - <int key="objectID">-3</int> - <reference key="object" ref="1004"/> - <reference key="parent" ref="0"/> - <string key="objectName">Application</string> - </object> - <object class="IBObjectRecord"> - <int key="objectID">1</int> - <reference key="object" ref="1005"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> - </object> - <reference key="parent" ref="0"/> - </object> - </object> - </object> - <object class="NSMutableDictionary" key="flattenedProperties"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSArray" key="dict.sortedKeys"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>-1.IBPluginDependency</string> - <string>-2.IBPluginDependency</string> - <string>-3.IBPluginDependency</string> - <string>1.IBPluginDependency</string> - </object> - <object class="NSArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - </object> - </object> - <object class="NSMutableDictionary" key="unlocalizedProperties"> - <bool key="EncodedWithXMLCoder">YES</bool> - <reference key="dict.sortedKeys" ref="0"/> - <reference key="dict.values" ref="0"/> - </object> - <nil key="activeLocalization"/> - <object class="NSMutableDictionary" key="localizations"> - <bool key="EncodedWithXMLCoder">YES</bool> - <reference key="dict.sortedKeys" ref="0"/> - <reference key="dict.values" ref="0"/> - </object> - <nil key="sourceID"/> - <int key="maxID">19</int> - </object> - <object class="IBClassDescriber" key="IBDocument.Classes"> - <object class="NSMutableArray" key="referencedPartialClassDescriptions"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="IBPartialClassDescription"> - <string key="className">InfoBarContainerController</string> - <string key="superclassName">NSViewController</string> - <object class="NSMutableDictionary" key="outlets"> - <string key="NS.key.0">resizeDelegate_</string> - <string key="NS.object.0">id</string> - </object> - <object class="NSMutableDictionary" key="toOneOutletInfosByName"> - <string key="NS.key.0">resizeDelegate_</string> - <object class="IBToOneOutletInfo" key="NS.object.0"> - <string key="name">resizeDelegate_</string> - <string key="candidateClassName">id</string> - </object> - </object> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBProjectSource</string> - <string key="minorKey">./Classes/InfoBarContainerController.h</string> - </object> - </object> - </object> - </object> - <int key="IBDocument.localizationMode">0</int> - <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string> - <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies"> - <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string> - <integer value="1050" key="NS.object.0"/> - </object> - <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults"> - <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string> - <real value="1070" key="NS.object.0"/> - </object> - <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies"> - <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string> - <integer value="3000" key="NS.object.0"/> - </object> - <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> - <int key="IBDocument.defaultPropertyAccessControl">3</int> - </data> -</archive> diff --git a/chrome/browser/infobars/infobar.cc b/chrome/browser/infobars/infobar.cc index 2dc1391..1f2cdb9 100644 --- a/chrome/browser/infobars/infobar.cc +++ b/chrome/browser/infobars/infobar.cc @@ -30,9 +30,6 @@ SkColor GetInfoBarBottomColor(InfoBarDelegate::Type infobar_type) { kWarningBackgroundColorBottom : kPageActionBackgroundColorBottom; } -// TODO(pkasting): Port Mac to use this. -#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK) || defined(OS_ANDROID) - InfoBar::InfoBar(InfoBarService* owner, InfoBarDelegate* delegate) : owner_(owner), delegate_(delegate), @@ -181,5 +178,3 @@ void InfoBar::MaybeDelete() { delegate_ = NULL; } } - -#endif // TOOLKIT_VIEWS || TOOLKIT_GTK || OS_ANDROID diff --git a/chrome/browser/infobars/infobar.h b/chrome/browser/infobars/infobar.h index 1c0fbb9..179ee18 100644 --- a/chrome/browser/infobars/infobar.h +++ b/chrome/browser/infobars/infobar.h @@ -26,9 +26,6 @@ typedef InfoBarDelegate InfoBarAddedDetails; typedef std::pair<InfoBarDelegate*, bool> InfoBarRemovedDetails; typedef std::pair<InfoBarDelegate*, InfoBarDelegate*> InfoBarReplacedDetails; -// TODO(pkasting): Port Mac to use this. -#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK) || defined(OS_ANDROID) - class InfoBarContainer; class InfoBarService; @@ -67,6 +64,9 @@ class InfoBar : public ui::AnimationDelegate { // delegate once it is invisible. void CloseSoon(); + // Changes the target height of the main ("bar") portion of the infobar. + void SetBarTargetHeight(int height); + const ui::SlideAnimation& animation() const { return animation_; } int arrow_height() const { return arrow_height_; } int arrow_target_height() const { return arrow_target_height_; } @@ -81,9 +81,6 @@ class InfoBar : public ui::AnimationDelegate { // NOTE: Subclasses should not call this if we're already unowned. void RemoveSelf(); - // Changes the target height of the main ("bar") portion of the infobar. - void SetBarTargetHeight(int height); - // Given a control with size |prefsize|, returns the centered y position // within us, taking into account animation so the control "slides in" (or // out) as we animate open and closed. @@ -135,8 +132,4 @@ class InfoBar : public ui::AnimationDelegate { DISALLOW_COPY_AND_ASSIGN(InfoBar); }; -#elif defined(OS_MACOSX) -#include "chrome/browser/ui/cocoa/infobars/infobar.h" -#endif - #endif // CHROME_BROWSER_INFOBARS_INFOBAR_H_ diff --git a/chrome/browser/infobars/infobar_container.cc b/chrome/browser/infobars/infobar_container.cc index 0ae38e0..3c8660c 100644 --- a/chrome/browser/infobars/infobar_container.cc +++ b/chrome/browser/infobars/infobar_container.cc @@ -4,9 +4,6 @@ #include "build/build_config.h" -// TODO(pkasting): Port Mac to use this. -#if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK) || defined(OS_ANDROID) - #include "chrome/browser/infobars/infobar_container.h" #include <algorithm> @@ -235,5 +232,3 @@ int InfoBarContainer::ArrowTargetHeightForInfoBar(size_t infobar_index) const { (InfoBar::kDefaultArrowTargetHeight - top_arrow_target_height_) * first_infobar_animation.GetCurrentValue()); } - -#endif // TOOLKIT_VIEWS || defined(TOOLKIT_GTK) || defined(OS_ANDROID) diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h index e117b06..28ee5f7 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.h +++ b/chrome/browser/ui/cocoa/browser_window_controller.h @@ -496,6 +496,9 @@ class WebContents; // positioned relative to. - (NSRect)omniboxPopupAnchorRect; +// Force a layout of info bars. +- (void)layoutInfoBars; + @end // @interface BrowserWindowController (TestingAPI) diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index 7717c7e..cc8c86e 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm @@ -1947,6 +1947,10 @@ willAnimateFromState:(BookmarkBar::State)oldState return [[toolbarView superview] convertRect:anchorRect toView:nil]; } +- (void)layoutInfoBars { + [self layoutSubviews]; +} + - (void)sheetDidEnd:(NSWindow*)sheet returnCode:(NSInteger)code context:(void*)context { diff --git a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm index 3e9a785..09a5a65 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm @@ -21,6 +21,7 @@ #import "chrome/browser/ui/cocoa/browser_window_controller_private.h" #import "chrome/browser/ui/cocoa/fast_resize_view.h" #import "chrome/browser/ui/cocoa/history_overlay_controller.h" +#import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" #import "chrome/browser/ui/cocoa/nsview_additions.h" #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h" @@ -108,10 +109,8 @@ class BrowserWindowControllerTest : public InProcessBrowserTest { browser()->tab_strip_model()->GetActiveWebContents(); InfoBarService* service = InfoBarService::FromWebContents(web_contents); - info_bar_delegate_.reset(new DummyInfoBar(service)); - [[controller() infoBarContainerController] - addInfoBar:info_bar_delegate_->CreateInfoBar(service) - animate:NO]; + scoped_ptr<InfoBarDelegate> info_bar_delegate(new DummyInfoBar(service)); + service->AddInfoBar(info_bar_delegate.Pass()); } NSView* GetViewWithID(ViewID view_id) const { @@ -163,8 +162,6 @@ class BrowserWindowControllerTest : public InProcessBrowserTest { } private: - scoped_ptr<InfoBarDelegate> info_bar_delegate_; - DISALLOW_COPY_AND_ASSIGN(BrowserWindowControllerTest); }; @@ -371,10 +368,7 @@ IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, popup_browser->tab_strip_model()->GetActiveWebContents(); InfoBarService* service = InfoBarService::FromWebContents(web_contents); scoped_ptr<InfoBarDelegate> info_bar_delegate(new DummyInfoBar(service)); - [[popupController infoBarContainerController] - addInfoBar:info_bar_delegate->CreateInfoBar(service) - animate:NO]; - + service->AddInfoBar(info_bar_delegate.Pass()); EXPECT_TRUE( [[popupController infoBarContainerController] shouldSuppressTopInfoBarTip]); diff --git a/chrome/browser/ui/cocoa/infobars/alternate_nav_infobar_controller.mm b/chrome/browser/ui/cocoa/infobars/alternate_nav_infobar_controller.mm index a8b784d..9d64080b 100644 --- a/chrome/browser/ui/cocoa/infobars/alternate_nav_infobar_controller.mm +++ b/chrome/browser/ui/cocoa/infobars/alternate_nav_infobar_controller.mm @@ -7,7 +7,7 @@ #include "base/logging.h" #include "base/strings/sys_string_conversions.h" #import "chrome/browser/ui/cocoa/hyperlink_text_view.h" -#include "chrome/browser/ui/cocoa/infobars/infobar.h" +#include "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" #include "chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h" #import "ui/base/cocoa/cocoa_event_utils.h" #include "ui/base/window_open_disposition.h" @@ -25,7 +25,7 @@ [self removeButtons]; AlternateNavInfoBarDelegate* delegate = - static_cast<AlternateNavInfoBarDelegate*>(delegate_); + static_cast<AlternateNavInfoBarDelegate*>([self delegate]); DCHECK(delegate); size_t offset = string16::npos; string16 message = delegate->GetMessageTextWithOffset(&offset); @@ -50,7 +50,7 @@ WindowOpenDisposition disposition = ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); AlternateNavInfoBarDelegate* delegate = - static_cast<AlternateNavInfoBarDelegate*>(delegate_); + static_cast<AlternateNavInfoBarDelegate*>([self delegate]); if (delegate->LinkClicked(disposition)) [self removeSelf]; } @@ -58,7 +58,9 @@ @end InfoBar* AlternateNavInfoBarDelegate::CreateInfoBar(InfoBarService* owner) { - AlternateNavInfoBarController* controller = - [[AlternateNavInfoBarController alloc] initWithDelegate:this owner:owner]; - return new InfoBar(controller, this); + scoped_ptr<InfoBarCocoa> infobar(new InfoBarCocoa(owner, this)); + base::scoped_nsobject<AlternateNavInfoBarController> controller( + [[AlternateNavInfoBarController alloc] initWithInfoBar:infobar.get()]); + infobar->set_controller(controller); + return infobar.release(); } diff --git a/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.mm b/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.mm index 145b41e..fb1af15 100644 --- a/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.mm +++ b/chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.mm @@ -37,9 +37,8 @@ NSButton* CreateNSButtonWithResourceIDAndParameter( [super dealloc]; } -- (id)initWithDelegate:(InfoBarDelegate*)delegate - owner:(InfoBarService*)owner { - if ((self = [super initWithDelegate:delegate owner:owner])) { +- (id)initWithInfoBar:(InfoBarCocoa*)infobar { + if ((self = [super initWithInfoBar:infobar])) { [self initializeExtraControls]; } return self; diff --git a/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller.mm b/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller.mm index 8b73673..b237083 100644 --- a/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller.mm +++ b/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller.mm @@ -8,7 +8,7 @@ #include "base/strings/sys_string_conversions.h" #include "chrome/browser/infobars/confirm_infobar_delegate.h" #import "chrome/browser/ui/cocoa/hyperlink_text_view.h" -#include "chrome/browser/ui/cocoa/infobars/infobar.h" +#include "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" #import "ui/base/cocoa/cocoa_event_utils.h" #include "ui/base/window_open_disposition.h" @@ -19,7 +19,7 @@ - (IBAction)ok:(id)sender { if (![self isOwned]) return; - if (delegate_->AsConfirmInfoBarDelegate()->Accept()) + if ([self delegate]->AsConfirmInfoBarDelegate()->Accept()) [self removeSelf]; } @@ -27,7 +27,7 @@ - (IBAction)cancel:(id)sender { if (![self isOwned]) return; - if (delegate_->AsConfirmInfoBarDelegate()->Cancel()) + if ([self delegate]->AsConfirmInfoBarDelegate()->Cancel()) [self removeSelf]; } @@ -35,7 +35,8 @@ // the return value of GetButtons(). We create each button if // required and position them to the left of the close button. - (void)addAdditionalControls { - ConfirmInfoBarDelegate* delegate = delegate_->AsConfirmInfoBarDelegate(); + ConfirmInfoBarDelegate* delegate = + [self delegate]->AsConfirmInfoBarDelegate(); DCHECK(delegate); int visibleButtons = delegate->GetButtons(); @@ -130,14 +131,16 @@ return; WindowOpenDisposition disposition = ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); - if (delegate_->AsConfirmInfoBarDelegate()->LinkClicked(disposition)) + if ([self delegate]->AsConfirmInfoBarDelegate()->LinkClicked(disposition)) [self removeSelf]; } @end InfoBar* ConfirmInfoBarDelegate::CreateInfoBar(InfoBarService* owner) { - ConfirmInfoBarController* controller = - [[ConfirmInfoBarController alloc] initWithDelegate:this owner:owner]; - return new InfoBar(controller, this); + scoped_ptr<InfoBarCocoa> infobar(new InfoBarCocoa(owner, this)); + base::scoped_nsobject<ConfirmInfoBarController> controller( + [[ConfirmInfoBarController alloc] initWithInfoBar:infobar.get()]); + infobar->set_controller(controller); + return infobar.release(); } diff --git a/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm b/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm index 2ef1404..9af8601 100644 --- a/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm @@ -10,6 +10,7 @@ #include "chrome/browser/infobars/confirm_infobar_delegate.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/ui/cocoa/cocoa_profile_test.h" +#import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" #include "chrome/browser/ui/cocoa/infobars/mock_confirm_infobar_delegate.h" #include "chrome/browser/ui/cocoa/run_loop_testing.h" @@ -35,15 +36,16 @@ using content::WebContents; @end -@interface InfoBarContainerTest : NSObject<InfoBarContainer> { +@interface InfoBarContainerTest : NSObject<InfoBarContainerControllerBase> { InfoBarController* controller_; } + - (id)initWithController:(InfoBarController*)controller; -- (void)willRemoveController:(InfoBarController*)controller; -- (void)removeController:(InfoBarController*)controller; + @end @implementation InfoBarContainerTest + - (id)initWithController:(InfoBarController*)controller { if ((self = [super init])) { controller_ = controller; @@ -51,17 +53,18 @@ using content::WebContents; return self; } -- (void)willRemoveController:(InfoBarController*)controller { +- (BrowserWindowController*)browserWindowController { + return nil; } -- (void)removeController:(InfoBarController*)controller { - DCHECK(controller_ == controller); - controller_ = nil; +- (BOOL)shouldSuppressTopInfoBarTip { + return NO; } -- (BrowserWindowController*)browserWindowController { - return nil; +- (CGFloat)infobarArrowX { + return 0; } + @end @interface TestConfirmInfoBarController : ConfirmInfoBarController @@ -70,7 +73,9 @@ using content::WebContents; @implementation TestConfirmInfoBarController - (void)removeSelf { - [self close]; + [self infobarWillClose]; + if ([self infobar]) + [self infobar]->CloseSoon(); } @end @@ -79,7 +84,7 @@ namespace { class ConfirmInfoBarControllerTest : public CocoaProfileTest, public MockConfirmInfoBarDelegate::Owner { public: - virtual void SetUp() { + virtual void SetUp() OVERRIDE { CocoaProfileTest::SetUp(); web_contents_.reset( WebContents::Create(WebContents::CreateParams(profile()))); @@ -88,8 +93,12 @@ class ConfirmInfoBarControllerTest : public CocoaProfileTest, InfoBarService* infobar_service = InfoBarService::FromWebContents(web_contents_.get()); delegate_ = new MockConfirmInfoBarDelegate(this); + infobar_.reset(new InfoBarCocoa(infobar_service, delegate_)); + controller_.reset([[TestConfirmInfoBarController alloc] - initWithDelegate:delegate_ owner:infobar_service]); + initWithInfoBar:infobar_.get()]); + infobar_->set_controller(controller_); + container_.reset( [[InfoBarContainerTest alloc] initWithController:controller_]); [controller_ setContainerController:container_]; @@ -99,7 +108,8 @@ class ConfirmInfoBarControllerTest : public CocoaProfileTest, closed_delegate_link_clicked_ = false; } - virtual void TearDown() { + virtual void TearDown() OVERRIDE { + [controller_ removeSelf]; if (delegate_) delete delegate_; CocoaProfileTest::TearDown(); @@ -125,6 +135,7 @@ class ConfirmInfoBarControllerTest : public CocoaProfileTest, } scoped_ptr<WebContents> web_contents_; + scoped_ptr<InfoBarCocoa> infobar_; }; diff --git a/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.mm b/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.mm index cf9976e..2df80ef 100644 --- a/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.mm +++ b/chrome/browser/ui/cocoa/infobars/extension_infobar_controller.mm @@ -13,7 +13,7 @@ #include "chrome/browser/ui/browser_finder.h" #import "chrome/browser/ui/cocoa/animatable_view.h" #import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu_controller.h" -#include "chrome/browser/ui/cocoa/infobars/infobar.h" +#include "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" #import "chrome/browser/ui/cocoa/menu_button.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" @@ -141,18 +141,17 @@ class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver { @implementation ExtensionInfoBarController -- (id)initWithDelegate:(InfoBarDelegate*)delegate - owner:(InfoBarService*)owner - window:(NSWindow*)window { - if ((self = [super initWithDelegate:delegate owner:owner])) { +- (id)initWithInfoBar:(InfoBarCocoa*)infobar + window:(NSWindow*)window { + if ((self = [super initWithInfoBar:infobar])) { window_ = window; dropdownButton_.reset([[MenuButton alloc] init]); [dropdownButton_ setOpenMenuOnClick:YES]; extensions::ExtensionHost* extensionHost = - delegate_->AsExtensionInfoBarDelegate()->extension_host(); - Browser* browser = - chrome::FindBrowserWithWebContents(owner->web_contents()); + [self delegate]->AsExtensionInfoBarDelegate()->extension_host(); + Browser* browser = chrome::FindBrowserWithWebContents( + [self infobar]->OwnerCocoa()->web_contents()); contextMenuController_.reset([[ExtensionActionContextMenuController alloc] initWithExtension:extensionHost->extension() browser:browser @@ -178,8 +177,8 @@ class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver { - (void)addAdditionalControls { [self removeButtons]; - extensionView_ = delegate_->AsExtensionInfoBarDelegate()->extension_host()-> - view()->native_view(); + extensionView_ = [self delegate]->AsExtensionInfoBarDelegate() + ->extension_host()->view()->native_view(); // Add the extension's RenderWidgetHostView to the view hierarchy of the // InfoBar and make sure to place it below the Close button. @@ -210,13 +209,8 @@ class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver { // needed is because the extension view's frame will not have changed in the // above case, so the NSViewFrameDidChangeNotification registered below will // never fire. - if (NSHeight(extensionFrame) > 0.0) { - NSSize infoBarSize = [[self view] frame].size; - infoBarSize.height = [self clampedExtensionViewHeight] + - kBottomBorderHeightPx; - [[self view] setFrameSize:infoBarSize]; - [infoBarView_ setFrameSize:infoBarSize]; - } + if (NSHeight(extensionFrame) > 0.0) + [self infobar]->SetBarTargetHeight([self clampedExtensionViewHeight]); [self adjustExtensionViewSize]; @@ -243,19 +237,11 @@ class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver { - (void)extensionViewFrameChanged { [self adjustExtensionViewSize]; - - AnimatableView* view = [self animatableView]; - NSRect infoBarFrame = [view frame]; - CGFloat newHeight = [self clampedExtensionViewHeight] + kBottomBorderHeightPx; - [infoBarView_ setPostsFrameChangedNotifications:NO]; - infoBarFrame.size.height = newHeight; - [infoBarView_ setFrame:infoBarFrame]; - [infoBarView_ setPostsFrameChangedNotifications:YES]; - [view animateToNewHeight:newHeight duration:kAnimationDuration]; + [self infobar]->SetBarTargetHeight([self clampedExtensionViewHeight]); } - (CGFloat)clampedExtensionViewHeight { - CGFloat height = delegate_->AsExtensionInfoBarDelegate()->height(); + CGFloat height = [self delegate]->AsExtensionInfoBarDelegate()->height(); return std::max(kToolbarMinHeightPx, std::min(height, kToolbarMaxHeightPx)); } @@ -280,12 +266,13 @@ class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver { @end InfoBar* ExtensionInfoBarDelegate::CreateInfoBar(InfoBarService* owner) { + scoped_ptr<InfoBarCocoa> infobar(new InfoBarCocoa(owner, this)); NSWindow* window = [(NSView*)owner->web_contents()->GetView()->GetContentNativeView() window]; - ExtensionInfoBarController* controller = - [[ExtensionInfoBarController alloc] initWithDelegate:this - owner:owner - window:window]; - return new InfoBar(controller, this); + base::scoped_nsobject<ExtensionInfoBarController> controller( + [[ExtensionInfoBarController alloc] initWithInfoBar:infobar.get() + window:window]); + infobar->set_controller(controller); + return infobar.release(); } diff --git a/chrome/browser/ui/cocoa/infobars/infobar.h b/chrome/browser/ui/cocoa/infobars/infobar.h deleted file mode 100644 index 3d70739..0000000 --- a/chrome/browser/ui/cocoa/infobars/infobar.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef CHROME_BROWSER_UI_COCOA_INFOBARS_INFOBAR_H_ -#define CHROME_BROWSER_UI_COCOA_INFOBARS_INFOBAR_H_ - -#include "base/logging.h" // for DCHECK - -#if defined(__OBJC__) -@class InfoBarController; -#else -class InfoBarController; -#endif - -// A C++ wrapper around an Objective-C InfoBarController. This class -// exists solely to be the return value for InfoBarDelegate::CreateInfoBar(), -// as defined in chrome/browser/infobars/confirm_infobar_delegate.h. This -// class would be analogous to the various bridge classes we already -// have, but since there is no pre-defined InfoBar interface, it is -// easier to simply throw away this object and deal with the -// controller directly rather than pass messages through a bridge. -// -// Callers should delete the returned InfoBar immediately after -// calling CreateInfoBar(), as the returned InfoBar* object is not -// pointed to by anyone. Expected usage: -// -// scoped_ptr<InfoBar> infobar(delegate->CreateInfoBar()); -// InfoBarController* controller = infobar->controller(); -// // Do something with the controller, and save a pointer so it can be -// // deleted later. |infobar| will be deleted automatically. - -class InfoBar { - public: - InfoBar(InfoBarController* controller, InfoBarDelegate* delegate) - : controller_(controller), delegate_(delegate) { - DCHECK(controller); - DCHECK(delegate); - } - - InfoBarController* controller() { - return controller_; - } - - InfoBarDelegate* delegate() { - return delegate_; - } - - private: - // Pointer to the infobar controller. Is never null. - InfoBarController* controller_; // weak - InfoBarDelegate* delegate_; - - DISALLOW_COPY_AND_ASSIGN(InfoBar); -}; - -#endif // CHROME_BROWSER_UI_COCOA_INFOBARS_INFOBAR_H_ diff --git a/chrome/browser/ui/cocoa/infobars/infobar_cocoa.h b/chrome/browser/ui/cocoa/infobars/infobar_cocoa.h new file mode 100644 index 0000000..e8f1a83 --- /dev/null +++ b/chrome/browser/ui/cocoa/infobars/infobar_cocoa.h @@ -0,0 +1,38 @@ +// Copyright 2013 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. + +#ifndef CHROME_BROWSER_UI_COCOA_INFOBARS_INFOBAR_COCOA_H_ +#define CHROME_BROWSER_UI_COCOA_INFOBARS_INFOBAR_COCOA_H_ + +#include "base/mac/scoped_nsobject.h" +#include "chrome/browser/infobars/infobar.h" + +@class InfoBarController; + +// The cocoa specific implementation of InfoBar. The real info bar logic is +// actually in InfoBarController. +class InfoBarCocoa : public InfoBar { + public: + InfoBarCocoa(InfoBarService* owner, InfoBarDelegate* delegate); + + virtual ~InfoBarCocoa(); + + InfoBarController* controller() const { return controller_; } + + void set_controller(InfoBarController* controller) { + controller_.reset([controller retain]); + } + + // These functions allow access to protected InfoBar functions. + void RemoveSelfCocoa(); + InfoBarService* OwnerCocoa(); + + private: + // The Objective-C class that contains most of the info bar logic. + base::scoped_nsobject<InfoBarController> controller_; + + DISALLOW_COPY_AND_ASSIGN(InfoBarCocoa); +}; + +#endif // CHROME_BROWSER_UI_COCOA_INFOBARS_INFOBAR_COCOA_H_ diff --git a/chrome/browser/ui/cocoa/infobars/infobar_cocoa.mm b/chrome/browser/ui/cocoa/infobars/infobar_cocoa.mm new file mode 100644 index 0000000..c015171 --- /dev/null +++ b/chrome/browser/ui/cocoa/infobars/infobar_cocoa.mm @@ -0,0 +1,27 @@ +// Copyright 2013 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 "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" + +const int InfoBar::kSeparatorLineHeight = 1; +const int InfoBar::kDefaultArrowTargetHeight = 11; +const int InfoBar::kMaximumArrowTargetHeight = 24; +const int InfoBar::kDefaultArrowTargetHalfWidth = kDefaultArrowTargetHeight; +const int InfoBar::kMaximumArrowTargetHalfWidth = 14; +const int InfoBar::kDefaultBarTargetHeight = 36; + +InfoBarCocoa::InfoBarCocoa(InfoBarService* owner, InfoBarDelegate* delegate) + : InfoBar(owner, delegate) { +} + +InfoBarCocoa::~InfoBarCocoa() { +} + +void InfoBarCocoa::RemoveSelfCocoa() { + RemoveSelf(); +} + +InfoBarService* InfoBarCocoa::OwnerCocoa() { + return owner(); +} diff --git a/chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.h b/chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.h new file mode 100644 index 0000000..fe65762 --- /dev/null +++ b/chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.h @@ -0,0 +1,36 @@ +// Copyright 2013 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. + +#ifndef CHROME_BROWSER_UI_COCOA_INFOBARS_INFOBAR_CONTAINER_COCOA_H_ +#define CHROME_BROWSER_UI_COCOA_INFOBARS_INFOBAR_CONTAINER_COCOA_H_ + +#include "chrome/browser/infobars/infobar_container.h" + +@class InfoBarContainerController; + +// The cocoa specific implementation of InfoBarContainer. This mostly serves as +// a bridge for InfoBarContainerController. +class InfoBarContainerCocoa : public InfoBarContainer, + public InfoBarContainer::Delegate { + public: + explicit InfoBarContainerCocoa(InfoBarContainerController* controller); + virtual ~InfoBarContainerCocoa(); + + private: + // InfoBarContainer: + virtual void PlatformSpecificAddInfoBar(InfoBar* infobar, + size_t position) OVERRIDE; + virtual void PlatformSpecificRemoveInfoBar(InfoBar* infobar) OVERRIDE; + + // InfoBarContainer::Delegate: + virtual SkColor GetInfoBarSeparatorColor() const OVERRIDE; + virtual void InfoBarContainerStateChanged(bool is_animating) OVERRIDE; + virtual bool DrawInfoBarArrows(int* x) const OVERRIDE; + + InfoBarContainerController* controller_; // weak, owns us. + + DISALLOW_COPY_AND_ASSIGN(InfoBarContainerCocoa); +}; + +#endif // CHROME_BROWSER_UI_COCOA_INFOBARS_INFOBAR_CONTAINER_COCOA_H_ diff --git a/chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.mm b/chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.mm new file mode 100644 index 0000000..969b18e --- /dev/null +++ b/chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.mm @@ -0,0 +1,43 @@ +// Copyright 2013 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. + +#import "chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.h" + +#import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" +#import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" + +InfoBarContainerCocoa::InfoBarContainerCocoa( + InfoBarContainerController* controller) + : InfoBarContainer(this), + controller_(controller) { +} + +InfoBarContainerCocoa::~InfoBarContainerCocoa() { + RemoveAllInfoBarsForDestruction(); +} + +void InfoBarContainerCocoa::PlatformSpecificAddInfoBar(InfoBar* infobar, + size_t position) { + InfoBarCocoa* infobar_cocoa = static_cast<InfoBarCocoa*>(infobar); + [controller_ addInfoBar:infobar_cocoa position:position]; +} + +void InfoBarContainerCocoa::PlatformSpecificRemoveInfoBar(InfoBar* infobar) { + InfoBarCocoa* infobar_cocoa = static_cast<InfoBarCocoa*>(infobar); + [controller_ removeInfoBar:infobar_cocoa]; +} + +SkColor InfoBarContainerCocoa::GetInfoBarSeparatorColor() const { + return SK_ColorBLACK; +} + +void InfoBarContainerCocoa::InfoBarContainerStateChanged(bool is_animating) { + [controller_ positionInfoBarsAndRedraw:is_animating]; +} + +bool InfoBarContainerCocoa::DrawInfoBarArrows(int* x) const { + if (x) + *x = [controller_ infobarArrowX]; + return ![controller_ shouldSuppressTopInfoBarTip]; +} diff --git a/chrome/browser/ui/cocoa/infobars/infobar_container_controller.h b/chrome/browser/ui/cocoa/infobars/infobar_container_controller.h index f645b79..d8044c5 100644 --- a/chrome/browser/ui/cocoa/infobars/infobar_container_controller.h +++ b/chrome/browser/ui/cocoa/infobars/infobar_container_controller.h @@ -10,13 +10,12 @@ #include "base/mac/scoped_nsobject.h" #include "base/memory/scoped_ptr.h" #import "chrome/browser/ui/cocoa/view_resizer.h" -#include "content/public/browser/notification_registrar.h" @class BrowserWindowController; @class InfoBarController; -class InfoBar; +class InfoBarCocoa; +class InfoBarContainerCocoa; class InfoBarDelegate; -class InfoBarNotificationObserver; class TabStripModel; namespace content { @@ -25,31 +24,19 @@ class WebContents; // Protocol for basic container methods, as needed by an InfoBarController. // This protocol exists to make mocking easier in unittests. -@protocol InfoBarContainer -- (void)willRemoveController:(InfoBarController*)controller; -- (void)removeController:(InfoBarController*)controller; +@protocol InfoBarContainerControllerBase - (BrowserWindowController*)browserWindowController; +- (BOOL)shouldSuppressTopInfoBarTip; +- (CGFloat)infobarArrowX; @end - -namespace infobars { - -// The height of an infobar without the tip. -const CGFloat kBaseHeight = 36.0; - -// The height of the infobar tip. -const CGFloat kTipHeight = 12.0; - -}; // namespace infobars - - // Controller for the infobar container view, which is the superview // of all the infobar views. This class owns zero or more // InfoBarControllers, which manage the infobar views. This class // also receives tab strip model notifications and handles // adding/removing infobars when needed. -@interface InfoBarContainerController : NSViewController <ViewResizer, - InfoBarContainer> { +@interface InfoBarContainerController + : NSViewController<InfoBarContainerControllerBase> { @private // Needed to send resize messages when infobars are added or removed. id<ViewResizer> resizeDelegate_; // weak @@ -60,83 +47,47 @@ const CGFloat kTipHeight = 12.0; // Holds the InfoBarControllers currently owned by this container. base::scoped_nsobject<NSMutableArray> infobarControllers_; - // Holds InfoBarControllers when they are in the process of animating out. - base::scoped_nsobject<NSMutableSet> closingInfoBars_; - - // Lets us registers for INFOBAR_ADDED/INFOBAR_REMOVED - // notifications. The actual notifications are sent to the - // InfoBarNotificationObserver object, which proxies them back to us. - content::NotificationRegistrar registrar_; - scoped_ptr<InfoBarNotificationObserver> infoBarObserver_; + // The C++ instance that bridges to the cross platform code. + scoped_ptr<InfoBarContainerCocoa> containerCocoa_; // If YES then the first info bar doesn't draw a tip. BOOL shouldSuppressTopInfoBarTip_; + + // If YES then an infobar animation is in progress. + BOOL isAnimating_; + + // The last overlap tip height. This is used to ensure that the info bar + // position is updated if the infobar height doesn't change but the overlap + // does change. + int oldOverlappingTipHeight_; } @property(nonatomic, assign) BOOL shouldSuppressTopInfoBarTip; - (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate; -// Informs the container that the |controller| is going to close. It adds the -// controller to |closingInfoBars_|. Once the animation is complete, the -// controller calls |-removeController:| to finalize cleanup. -- (void)willRemoveController:(InfoBarController*)controller; - -// Removes |controller| from the list of controllers in this container and -// removes its view from the view hierarchy. This method is safe to call while -// |controller| is still on the call stack. -- (void)removeController:(InfoBarController*)controller; - -// 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. +// Modifies this container to display infobars for the given |contents|. - (void)changeWebContents:(content::WebContents*)contents; // Stripped down version of TabStripModelObserverBridge:tabDetachedWithContents. -// Forwarded by BWC. Removes all infobars and deregisters for any notifications -// if |contents| is the current tab contents. +// Forwarded by BWC. Removes all infobars if |contents| is the current tab +// contents. - (void)tabDetachedWithContents:(content::WebContents*)contents; -// Returns the number of active infobars. This is -// |infobarControllers_ - closingInfoBars_|. -- (NSUInteger)infobarCount; - // Returns the amount of additional height the container view needs to draw the -// anti-spoofing tip. This will return 0 if |-infobarCount| is 0. This is the -// total amount of overlap for all infobars. +// anti-spoofing tip. This is the total amount of overlap for all infobars. - (CGFloat)overlappingTipHeight; -@end - - -@interface InfoBarContainerController (ForTheObserverAndTesting) +// Adds the given infobar. +- (void)addInfoBar:(InfoBarCocoa*)infobar + position:(NSUInteger)position; -// Adds the given infobar. Takes ownership of |infobar|. -- (void)addInfoBar:(InfoBar*)infobar animate:(BOOL)animate; - -// Closes all the infobar views for a given delegate, either immediately or by -// starting a close animation. -- (void)closeInfoBarsForDelegate:(InfoBarDelegate*)delegate - animate:(BOOL)animate; +// Removes the given infobar. +- (void)removeInfoBar:(InfoBarCocoa*)infobar; // Positions the infobar views in the container view and notifies // |browser_controller_| that it needs to resize the container view. -- (void)positionInfoBarsAndRedraw; - -@end - - -@interface InfoBarContainerController (JustForTesting) - -// Removes all infobar views. Infobars which were already closing will be -// completely closed (i.e. the InfoBarDelegate will be deleted and we'll get a -// callback to removeController). Other infobars will simply stop animating and -// disappear. Callers must call positionInfoBarsAndRedraw() after calling this -// method. -- (void)removeAllInfoBars; +- (void)positionInfoBarsAndRedraw:(BOOL)isAnimating; @end diff --git a/chrome/browser/ui/cocoa/infobars/infobar_container_controller.mm b/chrome/browser/ui/cocoa/infobars/infobar_container_controller.mm index f68a15e..f611090 100644 --- a/chrome/browser/ui/cocoa/infobars/infobar_container_controller.mm +++ b/chrome/browser/ui/cocoa/infobars/infobar_container_controller.mm @@ -3,81 +3,25 @@ // found in the LICENSE file. #include "base/logging.h" -#include "base/mac/bundle_locations.h" #include "base/mac/mac_util.h" -#include "chrome/browser/chrome_notification_types.h" +#include "base/message_loop/message_loop.h" #include "chrome/browser/infobars/confirm_infobar_delegate.h" #include "chrome/browser/infobars/infobar.h" +#include "chrome/browser/infobars/infobar_container.h" #include "chrome/browser/infobars/infobar_service.h" -#import "chrome/browser/ui/cocoa/animatable_view.h" #import "chrome/browser/ui/cocoa/browser_window_controller.h" +#import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" +#import "chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.h" #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" #import "chrome/browser/ui/cocoa/infobars/infobar_controller.h" +#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" #import "chrome/browser/ui/cocoa/view_id_util.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_source.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 content::NotificationObserver { - public: - InfoBarNotificationObserver(InfoBarContainerController* controller) - : controller_(controller) { - } - - private: - // NotificationObserver implementation - virtual void Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE { - InfoBarService* infobar_service = - content::Source<InfoBarService>(source).ptr(); - switch (type) { - case chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED: - [controller_ addInfoBar:content::Details<InfoBarAddedDetails>(details)-> - CreateInfoBar(infobar_service) - animate:YES]; - break; - - case chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED: { - InfoBarRemovedDetails* removed_details = - content::Details<InfoBarRemovedDetails>(details).ptr(); - [controller_ - closeInfoBarsForDelegate:removed_details->first - animate:(removed_details->second ? YES : NO)]; - break; - } - - case chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED: { - InfoBarReplacedDetails* replaced_details = - content::Details<InfoBarReplacedDetails>(details).ptr(); - [controller_ closeInfoBarsForDelegate:replaced_details->first - animate:NO]; - [controller_ addInfoBar:replaced_details->second-> - CreateInfoBar(infobar_service) - animate:NO]; - 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. -- (CGFloat)desiredHeight; +@interface InfoBarContainerController () +// Removes |controller| from the list of controllers in this container and +// removes its view from the view hierarchy. This method is safe to call while +// |controller| is still on the call stack. +- (void)removeController:(InfoBarController*)controller; @end @@ -87,50 +31,28 @@ class InfoBarNotificationObserver : public content::NotificationObserver { - (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate { DCHECK(resizeDelegate); - if ((self = [super initWithNibName:@"InfoBarContainer" - bundle:base::mac::FrameworkBundle()])) { - resizeDelegate_ = resizeDelegate; - infoBarObserver_.reset(new InfoBarNotificationObserver(self)); + if ((self = [super initWithNibName:nil bundle:nil])) { + base::scoped_nsobject<NSView> view( + [[NSView alloc] initWithFrame:NSZeroRect]); + [view setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; + view_id_util::SetID(view, VIEW_ID_INFO_BAR_CONTAINER); + [self setView:view]; - // 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]); - closingInfoBars_.reset([[NSMutableSet alloc] initWithCapacity:2]); + resizeDelegate_ = resizeDelegate; + containerCocoa_.reset(new InfoBarContainerCocoa(self)); + infobarControllers_.reset([[NSMutableArray alloc] init]); } return self; } - (void)dealloc { + // Delete the container so that any remaining infobars are removed. + containerCocoa_.reset(); DCHECK_EQ([infobarControllers_ count], 0U); - DCHECK_EQ([closingInfoBars_ count], 0U); view_id_util::UnsetID([self view]); [super dealloc]; } -- (void)awakeFromNib { - // The info bar container view is an ordinary NSView object, so we set its - // ViewID here. - view_id_util::SetID([self view], VIEW_ID_INFO_BAR_CONTAINER); -} - -- (void)willRemoveController:(InfoBarController*)controller { - [closingInfoBars_ addObject:controller]; -} - -- (void)removeController:(InfoBarController*)controller { - if (![infobarControllers_ containsObject:controller]) - return; - - // This code can be executed while InfoBarController 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]; - [closingInfoBars_ removeObject:controller]; - [self positionInfoBarsAndRedraw]; -} - - (BrowserWindowController*)browserWindowController { id controller = [[[self view] window] windowController]; if (![controller isKindOfClass:[BrowserWindowController class]]) @@ -138,30 +60,19 @@ class InfoBarNotificationObserver : public content::NotificationObserver { return controller; } -- (void)changeWebContents:(content::WebContents*)contents { - registrar_.RemoveAll(); - [self removeAllInfoBars]; - - currentWebContents_ = contents; - if (currentWebContents_) { - InfoBarService* infobarService = - InfoBarService::FromWebContents(currentWebContents_); - for (size_t i = 0; i < infobarService->infobar_count(); ++i) { - InfoBar* infobar = - infobarService->infobar_at(i)->CreateInfoBar(infobarService); - [self addInfoBar:infobar animate:NO]; - } +- (CGFloat)infobarArrowX { + LocationBarViewMac* locationBar = + [[self browserWindowController] locationBarBridge]; + return locationBar->GetPageInfoBubblePoint().x; +} - content::Source<InfoBarService> source(infobarService); - registrar_.Add(infoBarObserver_.get(), - chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, source); - registrar_.Add(infoBarObserver_.get(), - chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, source); - registrar_.Add(infoBarObserver_.get(), - chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED, source); +- (void)changeWebContents:(content::WebContents*)contents { + if (contents) { + containerCocoa_->ChangeInfoBarService( + InfoBarService::FromWebContents(contents)); + } else { + containerCocoa_->ChangeInfoBarService(NULL); } - - [self positionInfoBarsAndRedraw]; } - (void)tabDetachedWithContents:(content::WebContents*)contents { @@ -169,99 +80,37 @@ class InfoBarNotificationObserver : public content::NotificationObserver { [self changeWebContents:NULL]; } -- (NSUInteger)infobarCount { - return [infobarControllers_ count] - [closingInfoBars_ count]; -} - - (CGFloat)overlappingTipHeight { - return [self infobarCount] ? infobars::kTipHeight : 0; -} - -- (void)resizeView:(NSView*)view newHeight:(CGFloat)height { - NSRect frame = [view frame]; - frame.size.height = height; - [view setFrame:frame]; - [self positionInfoBarsAndRedraw]; -} - -- (void)setAnimationInProgress:(BOOL)inProgress { - if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)]) - [resizeDelegate_ setAnimationInProgress:inProgress]; -} - -- (void)setShouldSuppressTopInfoBarTip:(BOOL)flag { - if (shouldSuppressTopInfoBarTip_ == flag) - return; - shouldSuppressTopInfoBarTip_ = flag; - [self positionInfoBarsAndRedraw]; -} - -@end - -@implementation InfoBarContainerController (PrivateMethods) - -- (CGFloat)desiredHeight { - CGFloat height = 0; - - // Take out the height of the tip from the total size of the infobar so that - // the tip overlaps the preceding infobar when there is more than one infobar. - for (InfoBarController* controller in infobarControllers_.get()) - height += NSHeight([[controller view] frame]) - infobars::kTipHeight; - - // If there are any infobars, add a little extra room for the tip of the first - // infobar. - if (height) - height += infobars::kTipHeight; - - return height; + return containerCocoa_->GetVerticalOverlap(NULL); } -- (void)addInfoBar:(InfoBar*)infobar animate:(BOOL)animate { +- (void)addInfoBar:(InfoBarCocoa*)infobar + position:(NSUInteger)position { InfoBarController* controller = infobar->controller(); [controller setContainerController:self]; - [[controller animatableView] setResizeDelegate:self]; - [[self view] addSubview:[controller view]]; - [infobarControllers_ addObject:[controller autorelease]]; + [infobarControllers_ insertObject:controller atIndex:position]; - if (animate) - [controller animateOpen]; - else - [controller open]; - - delete infobar; + NSView* relativeView = nil; + if (position > 0) + relativeView = [[infobarControllers_ objectAtIndex:position - 1] view]; + [[self view] addSubview:[controller view] + positioned:NSWindowAbove + relativeTo:relativeView]; } -- (void)closeInfoBarsForDelegate:(InfoBarDelegate*)delegate - animate:(BOOL)animate { - for (InfoBarController* controller in - [NSArray arrayWithArray:infobarControllers_.get()]) { - if ([controller delegate] == delegate) { - [controller infobarWillClose]; - if (animate) - [controller animateClosed]; - else - [controller close]; - } - } +- (void)removeInfoBar:(InfoBarCocoa*)infobar { + [infobar->controller() infobarWillClose]; + [self removeController:infobar->controller()]; + base::MessageLoop::current()->DeleteSoon(FROM_HERE, infobar); } -- (void)removeAllInfoBars { - // stopAnimation can remove the infobar from infobarControllers_ if it was in - // the midst of closing, so copy the array so mutations won't cause problems. - for (InfoBarController* controller in - [NSArray arrayWithArray:infobarControllers_.get()]) { - [[controller animatableView] stopAnimation]; - // This code can be executed while InfoBarController 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]; +- (void)positionInfoBarsAndRedraw:(BOOL)isAnimating { + if (isAnimating_ != isAnimating) { + isAnimating_ = isAnimating; + if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)]) + [resizeDelegate_ setAnimationInProgress:isAnimating_]; } - [infobarControllers_ removeAllObjects]; - [closingInfoBars_ removeAllObjects]; -} -- (void)positionInfoBarsAndRedraw { NSRect containerBounds = [[self view] bounds]; int minY = 0; @@ -271,20 +120,47 @@ class InfoBarNotificationObserver : public content::NotificationObserver { // the others below. for (InfoBarController* controller in [infobarControllers_ reverseObjectEnumerator]) { - NSView* view = [controller view]; - NSRect frame = [view frame]; + NSRect frame; frame.origin.x = NSMinX(containerBounds); frame.origin.y = minY; frame.size.width = NSWidth(containerBounds); - [view setFrame:frame]; + frame.size.height = [controller infobar]->total_height(); + [[controller view] setFrame:frame]; - minY += NSHeight(frame) - infobars::kTipHeight; + minY += NSHeight(frame) - [controller infobar]->arrow_height(); + [controller layoutArrow]; + } + + int totalHeight = 0; + int overlap = containerCocoa_->GetVerticalOverlap(&totalHeight); - BOOL isTop = [controller isEqual:[infobarControllers_ objectAtIndex:0]]; - [controller setHasTip:!shouldSuppressTopInfoBarTip_ || !isTop]; + if (NSHeight([[self view] frame]) != totalHeight) { + [resizeDelegate_ resizeView:[self view] newHeight:totalHeight]; + } else if (oldOverlappingTipHeight_ != overlap) { + // If the infobar overlap changed but the height didn't change then + // explicitly ask for a layout. + [[self browserWindowController] layoutInfoBars]; } + oldOverlappingTipHeight_ = overlap; +} + +- (void)setShouldSuppressTopInfoBarTip:(BOOL)flag { + if (shouldSuppressTopInfoBarTip_ == flag) + return; + shouldSuppressTopInfoBarTip_ = flag; + [self positionInfoBarsAndRedraw:isAnimating_]; +} - [resizeDelegate_ resizeView:[self view] newHeight:[self desiredHeight]]; +- (void)removeController:(InfoBarController*)controller { + if (![infobarControllers_ containsObject:controller]) + return; + + // This code can be executed while InfoBarController 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]; } @end diff --git a/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm b/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm index 617cf3f..c40e891 100644 --- a/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm @@ -7,34 +7,42 @@ #import <Cocoa/Cocoa.h> #include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/cocoa_test_helper.h" +#include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/ui/cocoa/cocoa_profile_test.h" +#include "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" #include "chrome/browser/ui/cocoa/infobars/mock_confirm_infobar_delegate.h" #import "chrome/browser/ui/cocoa/view_resizer_pong.h" +#import "content/public/browser/web_contents.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" namespace { -class InfoBarContainerControllerTest : public CocoaTest { - virtual void SetUp() { - CocoaTest::SetUp(); +class InfoBarContainerControllerTest : public CocoaProfileTest { + virtual void SetUp() OVERRIDE { + CocoaProfileTest::SetUp(); + web_contents_.reset(content::WebContents::Create( + content::WebContents::CreateParams(profile()))); + InfoBarService::CreateForWebContents(web_contents_.get()); + resizeDelegate_.reset([[ViewResizerPong alloc] init]); ViewResizerPong *viewResizer = resizeDelegate_.get(); - controller_ = - [[InfoBarContainerController alloc] initWithResizeDelegate:viewResizer]; + controller_.reset([[InfoBarContainerController alloc] + initWithResizeDelegate:viewResizer]); NSView* view = [controller_ view]; [[test_window() contentView] addSubview:view]; } - virtual void TearDown() { + virtual void TearDown() OVERRIDE { [[controller_ view] removeFromSuperviewWithoutNeedingDisplay]; - [controller_ release]; - CocoaTest::TearDown(); + controller_.reset(); + CocoaProfileTest::TearDown(); } public: base::scoped_nsobject<ViewResizerPong> resizeDelegate_; - InfoBarContainerController* controller_; + base::scoped_nsobject<InfoBarContainerController> controller_; + scoped_ptr<content::WebContents> web_contents_; }; TEST_VIEW(InfoBarContainerControllerTest, [controller_ view]) @@ -42,46 +50,25 @@ TEST_VIEW(InfoBarContainerControllerTest, [controller_ view]) TEST_F(InfoBarContainerControllerTest, BWCPong) { // Call positionInfoBarsAndResize and check that |resizeDelegate_| got a // resize message. - [resizeDelegate_ setHeight:-1]; - [controller_ positionInfoBarsAndRedraw]; + [resizeDelegate_ resizeView:[controller_ view] newHeight:-1]; + [controller_ positionInfoBarsAndRedraw:NO]; EXPECT_NE(-1, [resizeDelegate_ height]); } TEST_F(InfoBarContainerControllerTest, AddAndRemoveInfoBars) { NSView* view = [controller_ view]; - // Add three infobars and then remove them. - // After each step check to make sure we have the correct number of - // infobar subviews. - // This delegate deletes itself when they're told their infobars have closed. InfoBarDelegate* confirmDelegate = new MockConfirmInfoBarDelegate(NULL); - [controller_ addInfoBar:confirmDelegate->CreateInfoBar(NULL) animate:NO]; + InfoBarService* infobar_service = + InfoBarService::FromWebContents(web_contents_.get()); + scoped_ptr<InfoBarCocoa> infobar(static_cast<InfoBarCocoa*>( + confirmDelegate->CreateInfoBar(infobar_service))); + [controller_ addInfoBar:infobar.get() position:0]; EXPECT_EQ(1U, [[view subviews] count]); - // Just to mix things up, remove them in a different order. - [controller_ closeInfoBarsForDelegate:confirmDelegate animate:NO]; - EXPECT_EQ(0U, [[view subviews] count]); -} - -TEST_F(InfoBarContainerControllerTest, RemoveAllInfoBars) { - NSView* view = [controller_ view]; - - // Add three infobars and then remove them all. - - // removeAllInfobars does not close these, so we stack-allocate them so - // they'll get cleaned up. - MockConfirmInfoBarDelegate confirmDelegate(NULL); - MockConfirmInfoBarDelegate confirmDelegate2(NULL); - InfoBarDelegate* confirmDelegatePtr = &confirmDelegate; - InfoBarDelegate* confirmDelegate2Ptr = &confirmDelegate2; - - [controller_ addInfoBar:confirmDelegatePtr->CreateInfoBar(NULL) animate:NO]; - [controller_ addInfoBar:confirmDelegate2Ptr->CreateInfoBar(NULL) animate:NO]; - EXPECT_EQ(2U, [[view subviews] count]); - - [controller_ removeAllInfoBars]; + [controller_ removeInfoBar:infobar.release()]; EXPECT_EQ(0U, [[view subviews] count]); } diff --git a/chrome/browser/ui/cocoa/infobars/infobar_controller.h b/chrome/browser/ui/cocoa/infobars/infobar_controller.h index f96e7b1..5948169 100644 --- a/chrome/browser/ui/cocoa/infobars/infobar_controller.h +++ b/chrome/browser/ui/cocoa/infobars/infobar_controller.h @@ -6,8 +6,8 @@ #include "base/mac/scoped_nsobject.h" -@class AnimatableView; -@protocol InfoBarContainer; +@protocol InfoBarContainerControllerBase; +class InfoBarCocoa; class InfoBarDelegate; class InfoBarService; @class InfoBarGradientView; @@ -18,9 +18,8 @@ class InfoBarService; // override addAdditionalControls to customize the UI. @interface InfoBarController : NSViewController<NSTextViewDelegate> { @private - id<InfoBarContainer> containerController_; // weak, owns us - InfoBarService* owner_; // weak - BOOL infoBarClosing_; + id<InfoBarContainerControllerBase> containerController_; // weak, owns us + InfoBarCocoa* infobar_; // weak, owns us @protected IBOutlet InfoBarGradientView* infoBarView_; @@ -30,21 +29,20 @@ class InfoBarService; IBOutlet NSButton* cancelButton_; IBOutlet NSButton* closeButton_; - // In rare instances, it can be possible for |delegate_| to delete itself - // while this controller is still alive. Always check |delegate_| against - // NULL before using it. - InfoBarDelegate* delegate_; // weak, can be NULL - // Text fields don't work as well with embedded links as text views, but // text views cannot conveniently be created in IB. The xib file contains // a text field |labelPlaceholder_| that's replaced by this text view |label_| // in -awakeFromNib. base::scoped_nsobject<NSTextView> label_; -}; +} + +@property(nonatomic, assign) + id<InfoBarContainerControllerBase> containerController; +@property(nonatomic, readonly) InfoBarDelegate* delegate; +@property(nonatomic, readonly) InfoBarCocoa* infobar; // Initializes a new InfoBarController. -- (id)initWithDelegate:(InfoBarDelegate*)delegate - owner:(InfoBarService*)owner; +- (id)initWithInfoBar:(InfoBarCocoa*)infobar; // Returns YES if the infobar is owned. If this is NO, it is not safe to call // any delegate functions, since they might attempt to access the owner. Code @@ -67,17 +65,6 @@ class InfoBarService; // call will trigger a notification that starts the infobar animating closed. - (void)removeSelf; -// Returns a pointer to this controller's view, cast as an AnimatableView. -- (AnimatableView*)animatableView; - -// Open or animate open the infobar. -- (void)open; -- (void)animateOpen; - -// Close or animate close the infobar. -- (void)close; -- (void)animateClosed; - // Subclasses can override this method to add additional controls to // the infobar view. This method is called by awakeFromNib. The // default implementation does nothing. @@ -91,10 +78,8 @@ class InfoBarService; // space. - (void)removeButtons; -- (void)setHasTip:(BOOL)hasTip; - -@property(nonatomic, assign) id<InfoBarContainer> containerController; -@property(nonatomic, readonly) InfoBarDelegate* delegate; +// Updates the view's arrow position. +- (void)layoutArrow; @end @@ -108,6 +93,3 @@ class InfoBarService; // InfoBarController subclasses, one for each InfoBarDelegate // subclass. Each of these subclasses overrides addAdditionalControls to // configure its view as necessary. - - - diff --git a/chrome/browser/ui/cocoa/infobars/infobar_controller.mm b/chrome/browser/ui/cocoa/infobars/infobar_controller.mm index 29e25d5..3a7d0d5 100644 --- a/chrome/browser/ui/cocoa/infobars/infobar_controller.mm +++ b/chrome/browser/ui/cocoa/infobars/infobar_controller.mm @@ -12,7 +12,8 @@ #import "chrome/browser/ui/cocoa/browser_window_controller.h" #import "chrome/browser/ui/cocoa/hyperlink_text_view.h" #import "chrome/browser/ui/cocoa/image_button_cell.h" -#include "chrome/browser/ui/cocoa/infobars/infobar.h" +#include "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" +#import "chrome/browser/ui/cocoa/infobars/infobar_container_cocoa.h" #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" #import "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h" #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" @@ -20,38 +21,21 @@ #include "grit/ui_resources.h" #include "ui/gfx/image/image.h" -namespace { -// Durations set to match the default SlideAnimation duration. -const float kAnimateOpenDuration = 0.12; -const float kAnimateCloseDuration = 0.12; -} - -@interface InfoBarController (PrivateMethods) +@interface InfoBarController () // Sets |label_| based on |labelPlaceholder_|, sets |labelPlaceholder_| to nil. - (void)initializeLabel; - -// Performs final cleanup after an animation is finished or stopped, including -// notifying the InfoBarDelegate that the infobar was closed and removing the -// infobar from its container, if necessary. -- (void)cleanUpAfterAnimation:(BOOL)finished; - -// Returns the point, in window coordinates, at which the apex of the infobar -// tip should be drawn. -- (NSPoint)pointForTipApex; @end @implementation InfoBarController @synthesize containerController = containerController_; -@synthesize delegate = delegate_; +@synthesize infobar = infobar_; -- (id)initWithDelegate:(InfoBarDelegate*)delegate - owner:(InfoBarService*)owner { - DCHECK(delegate); +- (id)initWithInfoBar:(InfoBarCocoa*)infobar { if ((self = [super initWithNibName:@"InfoBar" bundle:base::mac::FrameworkBundle()])) { - delegate_ = delegate; - owner_ = owner; + DCHECK(infobar); + infobar_ = infobar; } return self; } @@ -59,8 +43,6 @@ const float kAnimateCloseDuration = 0.12; // All infobars have an icon, so we set up the icon in the base class // awakeFromNib. - (void)awakeFromNib { - DCHECK(delegate_); - [[closeButton_ cell] setImageID:IDR_CLOSE_1 forButtonState:image_button_cell::kDefaultState]; [[closeButton_ cell] setImageID:IDR_CLOSE_1_H @@ -70,8 +52,8 @@ const float kAnimateCloseDuration = 0.12; [[closeButton_ cell] setImageID:IDR_CLOSE_1 forButtonState:image_button_cell::kDisabledState]; - if (!delegate_->GetIcon().IsEmpty()) { - [image_ setImage:delegate_->GetIcon().ToNSImage()]; + if (![self delegate]->GetIcon().IsEmpty()) { + [image_ setImage:[self delegate]->GetIcon().ToNSImage()]; } else { // No icon, remove it from the view and grow the textfield to include the // space. @@ -87,8 +69,7 @@ const float kAnimateCloseDuration = 0.12; [self addAdditionalControls]; - infoBarView_.tipApex = [self pointForTipApex]; - [infoBarView_ setInfobarType:delegate_->GetInfoBarType()]; + [infoBarView_ setInfobarType:[self delegate]->GetInfoBarType()]; } - (void)dealloc { @@ -108,7 +89,7 @@ const float kAnimateCloseDuration = 0.12; } - (BOOL)isOwned { - return !!owner_; + return infobar_->OwnerCocoa() != NULL; } // Called when someone clicks on the ok button. @@ -127,63 +108,12 @@ const float kAnimateCloseDuration = 0.12; - (void)dismiss:(id)sender { if (![self isOwned]) return; - delegate_->InfoBarDismissed(); + [self delegate]->InfoBarDismissed(); [self removeSelf]; } - (void)removeSelf { - // |owner_| should never be NULL here. If it is, then someone violated what - // they were supposed to do -- e.g. a ConfirmInfoBarDelegate subclass returned - // true from Accept() or Cancel() even though the infobar was already closing. - // In the worst case, if we also switched tabs during that process, then - // |this| has already been destroyed. But if that's the case, then we're - // going to deref a garbage |this| pointer here whether we check |owner_| or - // not, and in other cases (where we're still closing and |this| is valid), - // checking |owner_| here will avoid a NULL deref. - if (owner_) - owner_->RemoveInfoBar(delegate_); -} - -- (AnimatableView*)animatableView { - return static_cast<AnimatableView*>([self view]); -} - -- (void)open { - // Simply reset the frame size to its opened size, forcing a relayout. - CGFloat finalHeight = [[self view] frame].size.height; - [[self animatableView] setHeight:finalHeight]; -} - -- (void)animateOpen { - // Force the frame size to be 0 and then start an animation. - NSRect frame = [[self view] frame]; - CGFloat finalHeight = frame.size.height; - frame.size.height = 0; - [[self view] setFrame:frame]; - [[self animatableView] animateToNewHeight:finalHeight - duration:kAnimateOpenDuration]; -} - -- (void)close { - // Stop any running animations. - [[self animatableView] stopAnimation]; - infoBarClosing_ = YES; - [self cleanUpAfterAnimation:YES]; -} - -- (void)animateClosed { - // Notify the container of our intentions. - [containerController_ willRemoveController:self]; - - // Start animating closed. We will receive a notification when the animation - // is done, at which point we can remove our view from the hierarchy and - // notify the delegate that the infobar was closed. - [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration]; - - // The above call may trigger an animationDidStop: notification for any - // currently-running animations, so do not set |infoBarClosing_| until after - // starting the animation. - infoBarClosing_ = YES; + infobar_->RemoveSelfCocoa(); } - (void)addAdditionalControls { @@ -191,7 +121,6 @@ const float kAnimateCloseDuration = 0.12; } - (void)infobarWillClose { - owner_ = NULL; } - (void)removeButtons { @@ -205,8 +134,15 @@ const float kAnimateCloseDuration = 0.12; [label_.get() setFrame:labelFrame]; } -- (void)setHasTip:(BOOL)hasTip { - [infoBarView_ setHasTip:hasTip]; +- (void)layoutArrow { + [infoBarView_ setArrowHeight:infobar_->arrow_height()]; + [infoBarView_ setArrowHalfWidth:infobar_->arrow_half_width()]; + [infoBarView_ setHasTip:![containerController_ shouldSuppressTopInfoBarTip]]; + + // Convert from window to view coordinates. + NSPoint point = NSMakePoint([containerController_ infobarArrowX], 0); + point = [infoBarView_ convertPoint:point fromView:nil]; + [infoBarView_ setArrowX:point.x]; } - (void)disablePopUpMenu:(NSMenu*)menu { @@ -223,9 +159,9 @@ const float kAnimateCloseDuration = 0.12; } } -@end - -@implementation InfoBarController (PrivateMethods) +- (InfoBarDelegate*)delegate { + return infobar_->delegate(); +} - (void)initializeLabel { // Replace the label placeholder NSTextField with the real label NSTextView. @@ -241,42 +177,4 @@ const float kAnimateCloseDuration = 0.12; [label_.get() setDelegate:self]; } -- (void)cleanUpAfterAnimation:(BOOL)finished { - // Don't need to do any cleanup if the bar was animating open. - if (!infoBarClosing_) - return; - - if (delegate_) { - delete delegate_; - delegate_ = NULL; - } - - // If the animation ran to completion, then we need to remove ourselves from - // the container. If the animation was interrupted, then the container will - // take care of removing us. - // TODO(rohitrao): UGH! This works for now, but should be cleaner. - if (finished) - [containerController_ removeController:self]; -} - -- (void)animationDidStop:(NSAnimation*)animation { - [self cleanUpAfterAnimation:NO]; -} - -- (void)animationDidEnd:(NSAnimation*)animation { - [self cleanUpAfterAnimation:YES]; -} - -- (NSPoint)pointForTipApex { - BrowserWindowController* windowController = - [containerController_ browserWindowController]; - if (!windowController) { - // This should only happen in unit tests. - return NSZeroPoint; - } - - LocationBarViewMac* locationBar = [windowController locationBarBridge]; - return locationBar->GetPageInfoBubblePoint(); -} - @end diff --git a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h index 48fefc8..f78ec6a 100644 --- a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h +++ b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h @@ -13,13 +13,15 @@ // A custom view that draws the background gradient for an infobar. @interface InfoBarGradientView : VerticalGradientView { @private - NSPoint tipApex_; + CGFloat arrowHeight_; + CGFloat arrowHalfWidth_; + CGFloat arrowX_; BOOL hasTip_; } -// The point, in window coordinates, at which the infobar tip is the highest and -// pointing at the omnibox decoration. -@property(assign, nonatomic) NSPoint tipApex; +@property(assign, nonatomic) CGFloat arrowHeight; +@property(assign, nonatomic) CGFloat arrowHalfWidth; +@property(assign, nonatomic) CGFloat arrowX; @property(assign, nonatomic) BOOL hasTip; // Sets the infobar type. This will change the view's gradient. diff --git a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm index c86f463..12222de 100644 --- a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm +++ b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm @@ -14,15 +14,11 @@ #include "skia/ext/skia_utils_mac.h" #include "ui/base/theme_provider.h" -namespace { - -const CGFloat kTipWidth = 23; - -} // namespace - @implementation InfoBarGradientView -@synthesize tipApex = tipApex_; +@synthesize arrowHeight = arrowHeight_; +@synthesize arrowHalfWidth = arrowHalfWidth_; +@synthesize arrowX = arrowX_; @synthesize hasTip = hasTip_; - (id)initWithFrame:(NSRect)frame { @@ -61,11 +57,9 @@ const CGFloat kTipWidth = 23; - (void)drawRect:(NSRect)rect { NSRect bounds = [self bounds]; - bounds.size.height = infobars::kBaseHeight; + bounds.size.height = InfoBar::kDefaultBarTargetHeight; - const CGFloat kHalfWidth = kTipWidth / 2.0; - NSPoint localApex = [self convertPoint:self.tipApex fromView:nil]; - CGFloat tipXOffset = localApex.x - kHalfWidth; + CGFloat tipXOffset = arrowX_ - arrowHalfWidth_; // Around the bounds of the infobar, continue drawing the path into which the // gradient will be drawn. @@ -75,10 +69,10 @@ const CGFloat kTipWidth = 23; // Draw the tip. if (hasTip_) { [infoBarPath lineToPoint:NSMakePoint(tipXOffset, NSMaxY(bounds))]; - [infoBarPath relativeLineToPoint:NSMakePoint(kHalfWidth, - infobars::kTipHeight)]; - [infoBarPath relativeLineToPoint:NSMakePoint(kHalfWidth, - -infobars::kTipHeight)]; + [infoBarPath relativeLineToPoint:NSMakePoint(arrowHalfWidth_, + arrowHeight_)]; + [infoBarPath relativeLineToPoint:NSMakePoint(arrowHalfWidth_, + -arrowHeight_)]; } [infoBarPath lineToPoint:NSMakePoint(NSMaxX(bounds), NSMaxY(bounds))]; @@ -107,14 +101,14 @@ const CGFloat kTipWidth = 23; } // Add an inner stroke. - const CGFloat kHighlightTipHeight = infobars::kTipHeight - 1; + const CGFloat kHighlightTipHeight = arrowHeight_ - 1; NSBezierPath* highlightPath = [NSBezierPath bezierPath]; [highlightPath moveToPoint:NSMakePoint(NSMinX(bounds), NSMaxY(bounds) - 1)]; if (hasTip_) { [highlightPath relativeLineToPoint:NSMakePoint(tipXOffset + 1, 0)]; - [highlightPath relativeLineToPoint:NSMakePoint(kHalfWidth - 1, + [highlightPath relativeLineToPoint:NSMakePoint(arrowHalfWidth_ - 1, kHighlightTipHeight)]; - [highlightPath relativeLineToPoint:NSMakePoint(kHalfWidth - 1, + [highlightPath relativeLineToPoint:NSMakePoint(arrowHalfWidth_ - 1, -kHighlightTipHeight)]; } [highlightPath lineToPoint:NSMakePoint(NSMaxX(bounds), NSMaxY(bounds) - 1)]; diff --git a/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm b/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm index c5e5e63..964e1ed 100644 --- a/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm +++ b/chrome/browser/ui/cocoa/infobars/infobar_utilities.mm @@ -5,6 +5,7 @@ #import "chrome/browser/ui/cocoa/infobars/infobar_utilities.h" #include "base/mac/scoped_nsobject.h" +#import "chrome/browser/infobars/infobar.h" #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" #import "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h" @@ -47,7 +48,7 @@ void VerticallyCenterView(NSView* toMove) { // rather than in the total height (which includes the bulge). CGFloat superHeight = NSHeight(superViewFrame); if ([[toMove superview] isKindOfClass:[InfoBarGradientView class]]) - superHeight = infobars::kBaseHeight; + superHeight = InfoBar::kDefaultBarTargetHeight; viewFrame.origin.y = floor((superHeight - NSHeight(viewFrame)) / 2.0); [toMove setFrame:viewFrame]; diff --git a/chrome/browser/ui/cocoa/infobars/translate_infobar_base.mm b/chrome/browser/ui/cocoa/infobars/translate_infobar_base.mm index 8d8f2b7..5f9f7ba 100644 --- a/chrome/browser/ui/cocoa/infobars/translate_infobar_base.mm +++ b/chrome/browser/ui/cocoa/infobars/translate_infobar_base.mm @@ -11,7 +11,7 @@ #import "chrome/browser/ui/cocoa/hover_close_button.h" #include "chrome/browser/ui/cocoa/infobars/after_translate_infobar_controller.h" #import "chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.h" -#include "chrome/browser/ui/cocoa/infobars/infobar.h" +#include "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" #import "chrome/browser/ui/cocoa/infobars/infobar_controller.h" #import "chrome/browser/ui/cocoa/infobars/infobar_gradient_view.h" @@ -29,28 +29,27 @@ using InfoBarUtilities::AddMenuItem; // TranslateInfoBarDelegate views specific method: InfoBar* TranslateInfoBarDelegate::CreateInfoBar(InfoBarService* owner) { - TranslateInfoBarControllerBase* infobar_controller = NULL; + scoped_ptr<InfoBarCocoa> infobar(new InfoBarCocoa(owner, this)); + base::scoped_nsobject<TranslateInfoBarControllerBase> infobar_controller; switch (infobar_type_) { case BEFORE_TRANSLATE: - infobar_controller = - [[BeforeTranslateInfobarController alloc] initWithDelegate:this - owner:owner]; + infobar_controller.reset([[BeforeTranslateInfobarController alloc] + initWithInfoBar:infobar.get()]); break; case AFTER_TRANSLATE: - infobar_controller = - [[AfterTranslateInfobarController alloc] initWithDelegate:this - owner:owner]; + infobar_controller.reset([[AfterTranslateInfobarController alloc] + initWithInfoBar:infobar.get()]); break; case TRANSLATING: case TRANSLATION_ERROR: - infobar_controller = - [[TranslateMessageInfobarController alloc] initWithDelegate:this - owner:owner]; + infobar_controller.reset([[TranslateMessageInfobarController alloc] + initWithInfoBar:infobar.get()]); break; default: NOTREACHED(); } - return new InfoBar(infobar_controller, this); + infobar->set_controller(infobar_controller); + return infobar.release(); } @implementation TranslateInfoBarControllerBase (FrameChangeObserver) @@ -99,7 +98,7 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar(InfoBarService* owner) { @implementation TranslateInfoBarControllerBase - (TranslateInfoBarDelegate*)delegate { - return reinterpret_cast<TranslateInfoBarDelegate*>(delegate_); + return reinterpret_cast<TranslateInfoBarDelegate*>([super delegate]); } - (void)constructViews { diff --git a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm index 218e031..3195887 100644 --- a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm +++ b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm @@ -13,7 +13,7 @@ #include "chrome/browser/translate/translate_language_list.h" #include "chrome/browser/ui/cocoa/cocoa_profile_test.h" #import "chrome/browser/ui/cocoa/infobars/before_translate_infobar_controller.h" -#import "chrome/browser/ui/cocoa/infobars/infobar.h" +#import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" #import "chrome/browser/ui/cocoa/infobars/translate_infobar_base.h" #import "content/public/browser/web_contents.h" #include "ipc/ipc_message.h" @@ -88,10 +88,14 @@ class TranslationInfoBarTest : public CocoaProfileTest { infobar_delegate_.reset(new MockTranslateInfoBarDelegate( infobar_service, type, error, profile->GetPrefs(), config)); [[infobar_controller_ view] removeFromSuperview]; - scoped_ptr<InfoBar> infobar(static_cast<InfoBarDelegate*>( - infobar_delegate_.get())->CreateInfoBar(infobar_service)); - infobar_controller_.reset(reinterpret_cast<TranslateInfoBarControllerBase*>( - infobar->controller())); + + InfoBarDelegate* base = + static_cast<InfoBarDelegate*>(infobar_delegate_.get()); + infobar_.reset( + static_cast<InfoBarCocoa*>(base->CreateInfoBar(infobar_service))); + infobar_controller_.reset([static_cast<TranslateInfoBarControllerBase*>( + infobar_->controller()) retain]); + // We need to set the window to be wide so that the options button // doesn't overlap the other buttons. [test_window() setContentSize:NSMakeSize(2000, 500)]; @@ -101,6 +105,7 @@ class TranslationInfoBarTest : public CocoaProfileTest { scoped_ptr<WebContents> web_contents_; scoped_ptr<MockTranslateInfoBarDelegate> infobar_delegate_; + scoped_ptr<InfoBarCocoa> infobar_; base::scoped_nsobject<TranslateInfoBarControllerBase> infobar_controller_; }; diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 560b1a6..ff550f5 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -731,6 +731,10 @@ 'browser/ui/cocoa/infobars/confirm_infobar_controller.mm', 'browser/ui/cocoa/infobars/extension_infobar_controller.h', 'browser/ui/cocoa/infobars/extension_infobar_controller.mm', + 'browser/ui/cocoa/infobars/infobar_cocoa.h', + 'browser/ui/cocoa/infobars/infobar_cocoa.mm', + 'browser/ui/cocoa/infobars/infobar_container_cocoa.h', + 'browser/ui/cocoa/infobars/infobar_container_cocoa.mm', 'browser/ui/cocoa/infobars/infobar_container_controller.h', 'browser/ui/cocoa/infobars/infobar_container_controller.mm', 'browser/ui/cocoa/infobars/infobar_controller.h', @@ -739,9 +743,6 @@ 'browser/ui/cocoa/infobars/infobar_gradient_view.mm', 'browser/ui/cocoa/infobars/infobar_utilities.h', 'browser/ui/cocoa/infobars/infobar_utilities.mm', - 'browser/ui/cocoa/infobars/infobar.h', - 'browser/ui/cocoa/infobars/mock_confirm_infobar_delegate.cc', - 'browser/ui/cocoa/infobars/mock_confirm_infobar_delegate.h', 'browser/ui/cocoa/infobars/translate_infobar_base.h', 'browser/ui/cocoa/infobars/translate_infobar_base.mm', 'browser/ui/cocoa/infobars/translate_message_infobar_controller.h', diff --git a/chrome/chrome_nibs.gyp b/chrome/chrome_nibs.gyp index 2e12fc6..cdc4c52 100644 --- a/chrome/chrome_nibs.gyp +++ b/chrome/chrome_nibs.gyp @@ -167,18 +167,6 @@ 'browser/ui/cocoa/info_bubble_view.mm', 'browser/ui/cocoa/info_bubble_window.h', 'browser/ui/cocoa/info_bubble_window.mm', - 'browser/ui/cocoa/infobars/after_translate_infobar_controller.h', - 'browser/ui/cocoa/infobars/after_translate_infobar_controller.mm', - 'browser/ui/cocoa/infobars/alternate_nav_infobar_controller.h', - 'browser/ui/cocoa/infobars/alternate_nav_infobar_controller.mm', - 'browser/ui/cocoa/infobars/before_translate_infobar_controller.h', - 'browser/ui/cocoa/infobars/before_translate_infobar_controller.mm', - 'browser/ui/cocoa/infobars/confirm_infobar_controller.h', - 'browser/ui/cocoa/infobars/confirm_infobar_controller.mm', - 'browser/ui/cocoa/infobars/extension_infobar_controller.h', - 'browser/ui/cocoa/infobars/extension_infobar_controller.mm', - 'browser/ui/cocoa/infobars/infobar_container_controller.h', - 'browser/ui/cocoa/infobars/infobar_container_controller.mm', 'browser/ui/cocoa/infobars/infobar_controller.h', 'browser/ui/cocoa/infobars/infobar_controller.mm', 'browser/ui/cocoa/infobars/infobar_gradient_view.h', diff --git a/chrome/chrome_nibs.gypi b/chrome/chrome_nibs.gypi index 7c7aa33..aa4b2515 100644 --- a/chrome/chrome_nibs.gypi +++ b/chrome/chrome_nibs.gypi @@ -60,7 +60,6 @@ 'app/nibs/GlobalErrorBubble.xib', 'app/nibs/HungRendererDialog.xib', 'app/nibs/InfoBar.xib', - 'app/nibs/InfoBarContainer.xib', 'app/nibs/Notification.xib', 'app/nibs/Panel.xib', 'app/nibs/ScreenCaptureNotification.xib', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 2c1e640f..f49c7a7 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -1505,6 +1505,8 @@ 'browser/ui/cocoa/infobars/confirm_infobar_controller_unittest.mm', 'browser/ui/cocoa/infobars/infobar_container_controller_unittest.mm', 'browser/ui/cocoa/infobars/infobar_gradient_view_unittest.mm', + 'browser/ui/cocoa/infobars/mock_confirm_infobar_delegate.cc', + 'browser/ui/cocoa/infobars/mock_confirm_infobar_delegate.h', 'browser/ui/cocoa/infobars/translate_infobar_unittest.mm', 'browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm', 'browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm', |