diff options
24 files changed, 512 insertions, 441 deletions
diff --git a/chrome/app/nibs/InfoBarContainer.xib b/chrome/app/nibs/InfoBarContainer.xib index b7e5d8c..3ff7934 100644 --- a/chrome/app/nibs/InfoBarContainer.xib +++ b/chrome/app/nibs/InfoBarContainer.xib @@ -8,6 +8,7 @@ <string key="IBDocument.HIToolboxVersion">353.00</string> <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> <bool key="EncodedWithXMLCoder">YES</bool> + <integer value="1"/> </object> <object class="NSArray" key="IBDocument.PluginDependencies"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -34,9 +35,10 @@ <string key="NSClassName">NSApplication</string> </object> <object class="NSCustomView" id="1005"> - <nil key="NSNextResponder"/> + <reference key="NSNextResponder"/> <int key="NSvFlags">266</int> - <string key="NSFrameSize">{480, 30}</string> + <string key="NSFrameSize">{480, 0}</string> + <reference key="NSSuperview"/> <string key="NSClassName">NSView</string> </object> </object> @@ -108,7 +110,7 @@ <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>{{379, 587}, {480, 30}}</string> + <string>{{379, 617}, {480, 0}}</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>{628, 654}</string> <string>{{357, 416}, {480, 272}}</string> @@ -140,27 +142,35 @@ <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="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/infobar_container_controller.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> <string key="className">NSObject</string> <object class="IBClassDescriptionSource" key="sourceIdentifier"> <string key="majorKey">IBProjectSource</string> - <string key="minorKey">browser/cocoa/tab_strip_model_observer_bridge.h</string> + <string key="minorKey">browser/cocoa/status_bubble_mac.h</string> </object> </object> - </object> - <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.1+"> - <bool key="EncodedWithXMLCoder">YES</bool> <object class="IBPartialClassDescription"> - <string key="className">InfoBarContainerController</string> - <string key="superclassName">NSViewController</string> + <string key="className">NSObject</string> <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBDocumentRelativeSource</string> - <string key="minorKey">../../../browser/cocoa/infobar_container_controller.h</string> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/tab_strip_model_observer_bridge.h</string> </object> </object> </object> </object> <int key="IBDocument.localizationMode">0</int> - <string key="IBDocument.LastKnownRelativeProjectPath">../../../chrome.xcodeproj</string> + <string key="IBDocument.LastKnownRelativeProjectPath">../../chrome.xcodeproj</string> <int key="IBDocument.defaultPropertyAccessControl">3</int> </data> </archive> diff --git a/chrome/browser/cocoa/bookmark_bar_bridge_unittest.mm b/chrome/browser/cocoa/bookmark_bar_bridge_unittest.mm index 158069b..f260903 100644 --- a/chrome/browser/cocoa/bookmark_bar_bridge_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_bridge_unittest.mm @@ -32,15 +32,11 @@ typedef std::pair<GURL,WindowOpenDisposition> OpenInfo; @implementation FakeBookmarkBarController -- (id)initWithProfile:(Profile*)profile - parentView:(NSView*)parentView - webContentView:(NSView*)webContentView - infoBarsView:(NSView*)infoBarsView { +- (id)initWithProfile:(Profile*)profile { if ((self = [super initWithProfile:profile - parentView:parentView - webContentView:webContentView - infoBarsView:infoBarsView - delegate:self])) { + initialWidth:100 // arbitrary + resizeDelegate:nil + urlDelegate:self])) { callbacks_.reset([[NSMutableArray alloc] init]); } return self; @@ -96,14 +92,8 @@ typedef std::pair<GURL,WindowOpenDisposition> OpenInfo; class BookmarkBarBridgeTest : public testing::Test { public: - BookmarkBarBridgeTest() { - NSRect content_frame = NSMakeRect(0, 0, 100, 100); - view_.reset([[NSView alloc] initWithFrame:content_frame]); - } - CocoaTestHelper cocoa_helper_; BrowserTestHelper browser_test_helper_; - scoped_nsobject<NSView> view_; }; // Call all the callbacks; make sure they are all redirected to the objc object. @@ -119,11 +109,7 @@ TEST_F(BookmarkBarBridgeTest, TestRedirect) { [[NSView alloc] initWithFrame:NSMakeRect(0,0,100,100)]); scoped_nsobject<FakeBookmarkBarController> - controller([[FakeBookmarkBarController alloc] - initWithProfile:profile - parentView:parentView.get() - webContentView:webView.get() - infoBarsView:infoBarsView.get()]); + controller([[FakeBookmarkBarController alloc] initWithProfile:profile]); EXPECT_TRUE(controller.get()); scoped_ptr<BookmarkBarBridge> bridge(new BookmarkBarBridge(controller.get(), model)); diff --git a/chrome/browser/cocoa/bookmark_bar_controller.h b/chrome/browser/cocoa/bookmark_bar_controller.h index c035fc2..23b211c 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.h +++ b/chrome/browser/cocoa/bookmark_bar_controller.h @@ -20,6 +20,7 @@ class BookmarkNode; class GURL; class Profile; class PrefService; +@protocol ViewResizer; // The interface for an object which can open URLs for a bookmark. @protocol BookmarkURLOpener @@ -36,12 +37,8 @@ class PrefService; BookmarkModel* bookmarkModel_; // weak; part of the profile owned by the // top-level Browser object. - // Currently these two are always the same when not in fullscreen - // mode, but they mean slightly different things. - // contentAreaHasOffset_ is an implementation detail of bookmark bar - // show state. - BOOL contentViewHasOffset_; - BOOL barShouldBeShown_; + // Our initial view width, which is applied in awakeFromNib. + float initialWidth_; // BookmarkNodes have a 64bit id. NSMenuItems have a 32bit tag used // to represent the bookmark node they refer to. This map provides @@ -57,16 +54,18 @@ class PrefService; // Set when using fullscreen mode. BOOL barIsEnabled_; - NSView* parentView_; // weak; our parent view - NSView* webContentView_; // weak; where the web goes - NSView* infoBarsView_; // weak; where the infobars go + // Set to YES when the user elects to always show the bookmark bar. + BOOL barShouldBeShown_; // Bridge from Chrome-style C++ notifications (e.g. derived from // BookmarkModelObserver) scoped_ptr<BookmarkBarBridge> bridge_; - // Delegate which can open URLs for us. - id<BookmarkURLOpener> delegate_; // weak + // Delegate that can resize us. + id<ViewResizer> resizeDelegate_; // weak + + // Delegate that can open URLs for us. + id<BookmarkURLOpener> urlDelegate_; // weak IBOutlet NSView* buttonView_; IBOutlet NSButton* offTheSideButton_; @@ -74,15 +73,11 @@ class PrefService; } // Initializes the bookmark bar controller with the given browser -// profile, parent view (the toolbar), web content view, and delegate. -// |delegate| is used for opening URLs. -// TODO(rohitrao, jrg): The bookmark bar shouldn't know about the -// infoBarsView or the webContentView. +// profile and delegates. - (id)initWithProfile:(Profile*)profile - parentView:(NSView*)parentView - webContentView:(NSView*)webContentView - infoBarsView:(NSView*)infoBarsView - delegate:(id<BookmarkURLOpener>)delegate; + initialWidth:(float)initialWidth + resizeDelegate:(id<ViewResizer>)resizeDelegate + urlDelegate:(id<BookmarkURLOpener>)urlDelegate; // Returns whether or not the bookmark bar is visible. - (BOOL)isBookmarkBarVisible; @@ -138,7 +133,7 @@ class PrefService; // These APIs should only be used by unit tests (or used internally). @interface BookmarkBarController(InternalOrTestingAPI) // Set the delegate for a unit test. -- (void)setDelegate:(id<BookmarkURLOpener>)delegate; +- (void)setUrlDelegate:(id<BookmarkURLOpener>)urlDelegate; - (void)clearBookmarkBar; - (NSView*)buttonView; - (NSArray*)buttons; diff --git a/chrome/browser/cocoa/bookmark_bar_controller.mm b/chrome/browser/cocoa/bookmark_bar_controller.mm index d32ecbf..8fede00 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller.mm @@ -14,6 +14,7 @@ #import "chrome/browser/cocoa/bookmark_editor_controller.h" #import "chrome/browser/cocoa/bookmark_name_folder_controller.h" #import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h" +#import "chrome/browser/cocoa/view_resizer.h" #include "chrome/browser/cocoa/nsimage_cache.h" #include "chrome/browser/profile.h" #include "chrome/common/pref_names.h" @@ -31,15 +32,8 @@ namespace { -// TODO(jrg): this is the right proportional height but overlaps the -// "blue outline" of the omnibox. Fix. - // Our height, when opened. const int kBookmarkBarHeight = 30; -// How much to adjust our parent view. -const int kBookmarkBarSuperviewHeightAdjustment = 25; -// How much to adjust the web frame. -const int kBookmarkBarWebframeHeightAdjustment = 25; // Magic numbers from Cole const CGFloat kDefaultBookmarkWidth = 150.0; @@ -50,19 +44,17 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; @implementation BookmarkBarController - (id)initWithProfile:(Profile*)profile - parentView:(NSView*)parentView - webContentView:(NSView*)webContentView - infoBarsView:(NSView*)infoBarsView - delegate:(id<BookmarkURLOpener>)delegate { + initialWidth:(float)initialWidth + resizeDelegate:(id<ViewResizer>)resizeDelegate + urlDelegate:(id<BookmarkURLOpener>)urlDelegate { if ((self = [super initWithNibName:@"BookmarkBar" bundle:mac_util::MainAppBundle()])) { profile_ = profile; + initialWidth_ = initialWidth; bookmarkModel_ = profile->GetBookmarkModel(); - parentView_ = parentView; - webContentView_ = webContentView; - infoBarsView_ = infoBarsView; buttons_.reset([[NSMutableArray alloc] init]); - delegate_ = delegate; + resizeDelegate_ = resizeDelegate; + urlDelegate_ = urlDelegate; } return self; } @@ -75,14 +67,11 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; - (void)awakeFromNib { // We default to NOT open, which means height=0. DCHECK([[self view] isHidden]); // Hidden so it's OK to change. - NSRect frame = [[self view] frame]; - frame.size.height = 0; - frame.size.width = [parentView_ frame].size.width; - [[self view] setFrame:frame]; - - // Make sure the nodes stay bottom-aligned. - [[self view] setAutoresizingMask:(NSViewWidthSizable | - NSViewMinYMargin)]; + + // Set our initial height to zero, since that is what the superview + // expects. We will resize ourselves open later if needed. + [[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)]; + // Be sure to enable the bar before trying to show it... barIsEnabled_ = YES; if (profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar)) @@ -135,82 +124,16 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; // determine desired state. - (void)showBookmarkBar:(BOOL)show immediately:(BOOL)immediately { if (barIsEnabled_ && (barShouldBeShown_ != show)) { - contentViewHasOffset_ = show; - [[self view] setHidden:show ? NO : YES]; + if ([self view]) { + [[self view] setHidden:show ? NO : YES]; + [resizeDelegate_ resizeView:[self view] + newHeight:(show ? kBookmarkBarHeight : 0)]; + } barShouldBeShown_ = show; if (show) { [self loaded:bookmarkModel_]; } - [self applyContentAreaOffset:show immediately:immediately]; - } -} - -// Apply a contents box offset to make (or remove) room for the -// bookmark bar. If apply==YES, always make room (the contentView_ is -// "full size"). If apply==NO we are trying to undo an offset. If no -// offset there is nothing to undo. -// -// TODO(jrg): it is awkward we change the sizes of views for our -// parent and siblings; ideally they change their own sizes. -// -// TODO(jrg): unlike windows, we process events while an animator is -// running. Thus, if you resize the window while the bookmark bar is -// animating, you'll mess things up. Fix. -- (void)applyContentAreaOffset:(BOOL)apply immediately:(BOOL)immediately { - if ([self view] == nil) { - // We're too early, but awakeFromNib will call me again. - return; - } - if (!contentViewHasOffset_ && apply) { - // There is no offset to unconditionally apply. - return; - } - - // None of these locals are members of the Hall of Justice. - NSRect superframe = [parentView_ frame]; - NSRect frame = [[self view] frame]; - NSRect webframe = [webContentView_ frame]; - NSRect infoframe = [infoBarsView_ frame]; - if (apply) { - superframe.size.height += kBookmarkBarSuperviewHeightAdjustment; - // TODO(jrg): y=0 if we add the bookmark bar before the parent - // view (toolbar) is placed in the view hierarchy. A different - // CL, where the bookmark bar is extracted from the toolbar nib, - // may fix this awkwardness. - if (superframe.origin.y > 0) { - superframe.origin.y -= kBookmarkBarSuperviewHeightAdjustment; - webframe.size.height -= kBookmarkBarWebframeHeightAdjustment; - } - frame.size.height += kBookmarkBarHeight; - infoframe.origin.y -= kBookmarkBarWebframeHeightAdjustment; - } else { - superframe.size.height -= kBookmarkBarSuperviewHeightAdjustment; - superframe.origin.y += kBookmarkBarSuperviewHeightAdjustment; - frame.size.height -= kBookmarkBarHeight; - webframe.size.height += kBookmarkBarWebframeHeightAdjustment; - infoframe.origin.y += kBookmarkBarWebframeHeightAdjustment; } - - // TODO(jrg): Animators can be a little fussy. Setting these three - // off can sometimes causes races where the finish isn't as - // expected. Fix, or clean out the animators as an option. - // Odd racing is FAR worse than a lack of an animator. - if (1 /* immediately */) { - [parentView_ setFrame:superframe]; - [webContentView_ setFrame:webframe]; - [infoBarsView_ setFrame:infoframe]; - [[self view] setFrame:frame]; - } else { - [[parentView_ animator] setFrame:superframe]; - [[webContentView_ animator] setFrame:webframe]; - [[infoBarsView_ animator] setFrame:infoframe]; - [[[self view] animator] setFrame:frame]; - } - - [[self view] setNeedsDisplay:YES]; - [parentView_ setNeedsDisplay:YES]; - [webContentView_ setNeedsDisplay:YES]; - [infoBarsView_ setNeedsDisplay:YES]; } - (BOOL)isBookmarkBarVisible { @@ -259,7 +182,7 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; - (IBAction)openBookmark:(id)sender { BookmarkNode* node = [self nodeFromButton:sender]; - [delegate_ openBookmarkURL:node->GetURL() disposition:CURRENT_TAB]; + [urlDelegate_ openBookmarkURL:node->GetURL() disposition:CURRENT_TAB]; } // Given a NSMenuItem tag, return the appropriate bookmark node id. @@ -382,17 +305,17 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; - (IBAction)openBookmarkInNewForegroundTab:(id)sender { BookmarkNode* node = [self nodeFromMenuItem:sender]; - [delegate_ openBookmarkURL:node->GetURL() disposition:NEW_FOREGROUND_TAB]; + [urlDelegate_ openBookmarkURL:node->GetURL() disposition:NEW_FOREGROUND_TAB]; } - (IBAction)openBookmarkInNewWindow:(id)sender { BookmarkNode* node = [self nodeFromMenuItem:sender]; - [delegate_ openBookmarkURL:node->GetURL() disposition:NEW_WINDOW]; + [urlDelegate_ openBookmarkURL:node->GetURL() disposition:NEW_WINDOW]; } - (IBAction)openBookmarkInIncognitoWindow:(id)sender { BookmarkNode* node = [self nodeFromMenuItem:sender]; - [delegate_ openBookmarkURL:node->GetURL() disposition:OFF_THE_RECORD]; + [urlDelegate_ openBookmarkURL:node->GetURL() disposition:OFF_THE_RECORD]; } - (IBAction)editBookmark:(id)sender { @@ -431,7 +354,7 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; for (int i = 0; i < node->GetChildCount(); i++) { BookmarkNode* child = node->GetChild(i); if (child->is_url()) - [delegate_ openBookmarkURL:child->GetURL() + [urlDelegate_ openBookmarkURL:child->GetURL() disposition:NEW_BACKGROUND_TAB]; else [self openBookmarkNodesRecursive:child]; @@ -572,7 +495,7 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; - (IBAction)openBookmarkMenuItem:(id)sender { int64 tag = [self nodeIdFromMenuTag:[sender tag]]; const BookmarkNode* node = bookmarkModel_->GetNodeByID(tag); - [delegate_ openBookmarkURL:node->GetURL() disposition:CURRENT_TAB]; + [urlDelegate_ openBookmarkURL:node->GetURL() disposition:CURRENT_TAB]; } // Add all items from the given model to our bookmark bar. @@ -700,8 +623,8 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; [self loaded:model]; } -- (void)setDelegate:(id<BookmarkURLOpener>)delegate { - delegate_ = delegate; +- (void)setUrlDelegate:(id<BookmarkURLOpener>)urlDelegate { + urlDelegate_ = urlDelegate; } - (NSArray*)buttons { diff --git a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm index 2f4b9f6..161f12a 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm @@ -9,6 +9,7 @@ #import "chrome/browser/cocoa/bookmark_bar_controller.h" #include "chrome/browser/cocoa/browser_test_helper.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" +#import "chrome/browser/cocoa/view_resizer_pong.h" #include "testing/gtest/include/gtest/gtest.h" // Pretend BookmarkURLOpener delegate to keep track of requests @@ -81,21 +82,15 @@ static const int kInfoBarViewHeight = 30; class BookmarkBarControllerTest : public testing::Test { public: BookmarkBarControllerTest() { - NSRect content_frame = NSMakeRect(0, 0, 800, kContentAreaHeight); - // |infobar_frame| is set to be directly above |content_frame|. - NSRect infobar_frame = NSMakeRect(0, kContentAreaHeight, - 800, kInfoBarViewHeight); + resizeDelegate_.reset([[ViewResizerPong alloc] init]); NSRect parent_frame = NSMakeRect(0, 0, 800, 50); - content_area_.reset([[NSView alloc] initWithFrame:content_frame]); - infobar_view_.reset([[NSView alloc] initWithFrame:infobar_frame]); parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]); [parent_view_ setHidden:YES]; bar_.reset( [[BookmarkBarController alloc] initWithProfile:helper_.profile() - parentView:parent_view_.get() - webContentView:content_area_.get() - infoBarsView:infobar_view_.get() - delegate:nil]); + initialWidth:NSWidth(parent_frame) + resizeDelegate:resizeDelegate_.get() + urlDelegate:nil]); InstallAndToggleBar(bar_.get()); @@ -139,10 +134,9 @@ class BookmarkBarControllerTest : public testing::Test { CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... - scoped_nsobject<NSView> content_area_; - scoped_nsobject<NSView> infobar_view_; scoped_nsobject<NSView> parent_view_; BrowserTestHelper helper_; + scoped_nsobject<ViewResizerPong> resizeDelegate_; scoped_nsobject<BookmarkBarController> bar_; scoped_nsobject<NSMenu> menu_; scoped_nsobject<NSMenuItem> menu_item_; @@ -164,22 +158,14 @@ TEST_F(BookmarkBarControllerTest, ShowHide) { [bar_ toggleBookmarkBar]; EXPECT_TRUE([bar_ isBookmarkBarVisible]); EXPECT_FALSE([[bar_ view] isHidden]); - NSRect content_frame = [content_area_ frame]; - NSRect infobar_frame = [infobar_view_ frame]; - EXPECT_NE(content_frame.size.height, kContentAreaHeight); - EXPECT_EQ(NSMaxY(content_frame), NSMinY(infobar_frame)); - EXPECT_EQ(kInfoBarViewHeight, infobar_frame.size.height); + EXPECT_GT([resizeDelegate_ height], 0); EXPECT_GT([[bar_ view] frame].size.height, 0); [bar_ toggleBookmarkBar]; EXPECT_FALSE([bar_ isBookmarkBarVisible]); EXPECT_TRUE([[bar_ view] isHidden]); - content_frame = [content_area_ frame]; - infobar_frame = [infobar_view_ frame]; - EXPECT_EQ(content_frame.size.height, kContentAreaHeight); - EXPECT_EQ(NSMaxY(content_frame), NSMinY(infobar_frame)); - EXPECT_EQ(kInfoBarViewHeight, infobar_frame.size.height); - EXPECT_EQ([[bar_ view] frame].size.height, 0); + EXPECT_EQ(0, [resizeDelegate_ height]); + EXPECT_EQ(0, [[bar_ view] frame].size.height); } // Make sure we're watching for frame change notifications. @@ -188,10 +174,9 @@ TEST_F(BookmarkBarControllerTest, FrameChangeNotification) { bar.reset( [[BookmarkBarControllerTogglePong alloc] initWithProfile:helper_.profile() - parentView:parent_view_.get() - webContentView:content_area_.get() - infoBarsView:infobar_view_.get() - delegate:nil]); + initialWidth:100 // arbitrary + resizeDelegate:resizeDelegate_.get() + urlDelegate:nil]); InstallAndToggleBar(bar.get()); EXPECT_GT([bar toggles], 0); @@ -294,7 +279,7 @@ TEST_F(BookmarkBarControllerTest, OpenBookmark) { scoped_ptr<BookmarkNode> node(new BookmarkNode(gurl)); scoped_nsobject<BookmarkURLOpenerPong> pong([[BookmarkURLOpenerPong alloc] init]); - [bar_ setDelegate:pong.get()]; + [bar_ setUrlDelegate:pong.get()]; scoped_nsobject<NSButtonCell> cell([[NSButtonCell alloc] init]); scoped_nsobject<NSButton> button([[NSButton alloc] init]); @@ -305,7 +290,7 @@ TEST_F(BookmarkBarControllerTest, OpenBookmark) { EXPECT_EQ(pong.get()->urls_[0], node->GetURL()); EXPECT_EQ(pong.get()->dispositions_[0], CURRENT_TAB); - [bar_ setDelegate:nil]; + [bar_ setUrlDelegate:nil]; } // Confirm opening of bookmarks works from the menus (different @@ -313,7 +298,7 @@ TEST_F(BookmarkBarControllerTest, OpenBookmark) { TEST_F(BookmarkBarControllerTest, OpenBookmarkFromMenus) { scoped_nsobject<BookmarkURLOpenerPong> pong([[BookmarkURLOpenerPong alloc] init]); - [bar_ setDelegate:pong.get()]; + [bar_ setUrlDelegate:pong.get()]; const char* urls[] = { "http://walla.walla.ding.dong.com", "http://i_dont_know.com", @@ -334,7 +319,7 @@ TEST_F(BookmarkBarControllerTest, OpenBookmarkFromMenus) { EXPECT_EQ(pong.get()->dispositions_[0], dispositions[i]); [pong clear]; } - [bar_ setDelegate:nil]; + [bar_ setUrlDelegate:nil]; } TEST_F(BookmarkBarControllerTest, TestAddRemoveAndClear) { @@ -458,7 +443,7 @@ TEST_F(BookmarkBarControllerTest, DeleteBookmark) { TEST_F(BookmarkBarControllerTest, OpenAllBookmarks) { scoped_nsobject<BookmarkURLOpenerPong> pong([[BookmarkURLOpenerPong alloc] init]); - [bar_ setDelegate:pong.get()]; + [bar_ setUrlDelegate:pong.get()]; BookmarkModel* model = helper_.profile()->GetBookmarkModel(); const BookmarkNode* parent = model->GetBookmarkBarNode(); @@ -493,7 +478,7 @@ TEST_F(BookmarkBarControllerTest, OpenAllBookmarks) { EXPECT_EQ(pong.get()->dispositions_[3], NEW_BACKGROUND_TAB); - [bar_ setDelegate:nil]; + [bar_ setUrlDelegate:nil]; } // TODO(jrg): write a test to confirm that nodeFavIconLoaded calls diff --git a/chrome/browser/cocoa/browser_window_controller.h b/chrome/browser/cocoa/browser_window_controller.h index 382acf2..5ebbbf0 100644 --- a/chrome/browser/cocoa/browser_window_controller.h +++ b/chrome/browser/cocoa/browser_window_controller.h @@ -16,6 +16,7 @@ #include "base/scoped_ptr.h" #import "chrome/browser/cocoa/tab_window_controller.h" #import "chrome/browser/cocoa/bookmark_bar_controller.h" +#import "chrome/browser/cocoa/view_resizer.h" #import "third_party/GTM/AppKit/GTMTheme.h" class Browser; @@ -37,6 +38,7 @@ class TabStripModelObserverBridge; @interface BrowserWindowController : TabWindowController<NSUserInterfaceValidations, BookmarkURLOpener, + ViewResizer, GTMThemeDelegate> { @private // The ordering of these members is important as it determines the order in @@ -124,10 +126,6 @@ class TabStripModelObserverBridge; // Returns fullscreen state. - (BOOL)isFullscreen; -// Sent when the infobar view has been resized and other content needs -// to be shifted around it. -- (void)infoBarResized:(float)newHeight; - // The user changed the theme. - (void)userChangedTheme; diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm index a6c3012..bb073ec 100644 --- a/chrome/browser/cocoa/browser_window_controller.mm +++ b/chrome/browser/cocoa/browser_window_controller.mm @@ -66,20 +66,12 @@ const int kWindowGradientHeight = 24; @interface BrowserWindowController(Private) -- (void)positionInfoBar; -- (void)positionBar; // toolbar or URL bar -- (void)removeBar; // toolbar or URL bar - // Leopard's gradient heuristic gets confused by our tabs and makes the title // gradient jump when creating a tab that is less than a tab width from the // right side of the screen. This function disables Leopard's gradient // heuristic. - (void)fixWindowGradient; -// Called by the Notification Center whenever the tabContentArea's -// frame changes. Re-positions the bookmark bar and the find bar. -- (void)tabContentAreaFrameChanged:(id)sender; - // Saves the window's position in the local state preferences. - (void)saveWindowPositionIfNeeded; @@ -97,6 +89,9 @@ willPositionSheet:(NSWindow*)sheet // Theme up the window. - (void)applyTheme; + +// Repositions the windows subviews. +- (void)layoutSubviews; @end @@ -165,12 +160,12 @@ willPositionSheet:(NSWindow*)sheet model:browser_->tabstrip_model()]); // Create the infobar container view, so we can pass it to the - // ToolbarController, but do not position the view until after the - // toolbar is in place, as positionToolbar will move the tab content area. + // ToolbarController. infoBarContainerController_.reset( [[InfoBarContainerController alloc] initWithTabStripModel:(browser_->tabstrip_model()) - browserWindowController:self]); + resizeDelegate:self]); + [[[self window] contentView] addSubview:[infoBarContainerController_ view]]; // Create a controller for the toolbar, giving it the toolbar model object // and the toolbar view from the nib. The controller will handle @@ -179,30 +174,19 @@ willPositionSheet:(NSWindow*)sheet initWithModel:browser->toolbar_model() commands:browser->command_updater() profile:browser->profile() - webContentView:[self tabContentArea] - infoBarsView:[infoBarContainerController_ view] + resizeDelegate:self bookmarkDelegate:self]); // If we are a pop-up, we have a titlebar and no toolbar. if (!browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) && browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR)) { [toolbarController_ setHasToolbar:NO]; } - [self positionBar]; - [self fixWindowGradient]; + [[[self window] contentView] addSubview:[toolbarController_ view]]; - // Put the infobar container view into the window above the - // tabcontentarea. There are no infobars when starting up, so its - // initial height is 0. - [self positionInfoBar]; + [self fixWindowGradient]; - // Register ourselves for frame changed notifications from the - // tabContentArea. This has to come after all of the resizing and - // positioning above. - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(tabContentAreaFrameChanged:) - name:nil - object:[self tabContentArea]]; + // Force a relayout of all the various bars. + [self layoutSubviews]; // Create the bridge for the status bubble. statusBubble_.reset(new StatusBubbleMac([self window], self)); @@ -236,7 +220,6 @@ willPositionSheet:(NSWindow*)sheet // window destruction. [window_ setDelegate:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } @@ -338,8 +321,6 @@ willPositionSheet:(NSWindow*)sheet } } - - // Called when the user clicks the zoom button (or selects it from the Window // menu). Zoom to the appropriate size based on the content. Make sure we // enforce a minimum width to ensure websites with small intrinsic widths @@ -372,6 +353,32 @@ willPositionSheet:(NSWindow*)sheet return frame; } +// Main method to resize browser window subviews. This method should be called +// when resizing any child of the content view, rather than resizing the views +// directly. If the view is already the correct height, does not force a +// relayout. +- (void)resizeView:(NSView*)view newHeight:(float)height { + // We should only ever be called for one of the following three views. + // |downloadShelfController_| may be nil. + DCHECK(view); + DCHECK(view == [toolbarController_ view] || + view == [infoBarContainerController_ view] || + view == [downloadShelfController_ view]); + + // Change the height of the view and call layoutViews. We set the height here + // without regard to where the view is on the screen or whether it needs to + // "grow up" or "grow down." The below call to layoutSubviews will position + // each view correctly. + NSRect frame = [view frame]; + if (frame.size.height == height) + return; + + frame.size.height = height; + // TODO(rohitrao): Determine if calling setFrame: twice is bad. + [view setFrame:frame]; + [self layoutSubviews]; +} + // Update a toggle state for an NSMenuItem if modified. // Take care to insure |item| looks like a NSMenuItem. // Called by validateUserInterfaceItem:. @@ -708,7 +715,9 @@ willPositionSheet:(NSWindow*)sheet - (DownloadShelfController*)downloadShelf { if (!downloadShelfController_.get()) { downloadShelfController_.reset([[DownloadShelfController alloc] - initWithBrowser:browser_.get() contentArea:[self tabContentArea]]); + initWithBrowser:browser_.get() resizeDelegate:self]); + [[[self window] contentView] addSubview:[downloadShelfController_ view]]; + [downloadShelfController_ show:nil]; } return downloadShelfController_; } @@ -719,8 +728,11 @@ willPositionSheet:(NSWindow*)sheet // Create a controller for the findbar. findBarCocoaController_.reset([findBarCocoaController retain]); - [[[self window] contentView] addSubview:[findBarCocoaController_ view]]; - [findBarCocoaController_ positionFindBarView:[self tabContentArea]]; + [[[self window] contentView] addSubview:[findBarCocoaController_ view] + positioned:NSWindowAbove + relativeTo:[toolbarController_ view]]; + [findBarCocoaController_ + positionFindBarView:[infoBarContainerController_ view]]; } // Adjust the UI for fullscreen mode. E.g. when going fullscreen, @@ -729,18 +741,23 @@ willPositionSheet:(NSWindow*)sheet if (fullscreen) { // Disable showing of the bookmark bar. This does not toggle the // preference. + // TODO(jrg): Is this still necessary? [[toolbarController_ bookmarkBarController] setBookmarkBarEnabled:NO]; // Make room for more content area. - [self removeBar]; + [[toolbarController_ view] removeFromSuperview]; // Hide the menubar, and allow it to un-hide when moving the mouse // to the top of the screen. Does this eliminate the need for an // info bubble describing how to exit fullscreen mode? SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar); } else { SetSystemUIMode(kUIModeNormal, 0); - [self positionBar]; + [[[self window] contentView] addSubview:[toolbarController_ view]]; + // TODO(jrg): Is this still necessary? [[toolbarController_ bookmarkBarController] setBookmarkBarEnabled:YES]; } + + // Force a relayout. + [self layoutSubviews]; } - (NSWindow*)fullscreenWindow { @@ -751,24 +768,27 @@ willPositionSheet:(NSWindow*)sheet - (void)setFullscreen:(BOOL)fullscreen { fullscreen_ = fullscreen; if (fullscreen) { - // Minimize our UI - [self adjustUIForFullscreen:fullscreen]; // Move content to a new fullscreen window NSView* content = [[self window] contentView]; fullscreen_window_.reset([[self fullscreenWindow] retain]); [content removeFromSuperview]; [fullscreen_window_ setContentView:content]; [self setWindow:fullscreen_window_.get()]; + // Minimize our UI. This call triggers a relayout, so it needs to come + // after we move the contentview to the new window. + [self adjustUIForFullscreen:fullscreen]; // Show one window, hide the other. [fullscreen_window_ makeKeyAndOrderFront:self]; [content setNeedsDisplay:YES]; [window_ orderOut:self]; } else { - [self adjustUIForFullscreen:fullscreen]; NSView* content = [fullscreen_window_ contentView]; [content removeFromSuperview]; [window_ setContentView:content]; [self setWindow:window_.get()]; + // This call triggers a relayout, so it needs to come after we move the + // contentview to the new window. + [self adjustUIForFullscreen:fullscreen]; [content setNeedsDisplay:YES]; // With this call, valgrind yells at me about "Conditional jump or @@ -851,22 +871,6 @@ willPositionSheet:(NSWindow*)sheet [tabStripController_ userChangedTheme]; } -// TODO(rohitrao, jrg): Move this logic out of BrowserWindowController? -- (void)infoBarResized:(float)newHeight { - // The top edge of the infobar is fixed. - NSView* infoBarView = [infoBarContainerController_ view]; - NSRect infoBarFrame = [infoBarView frame]; - int maxY = NSMaxY(infoBarFrame); - int minY = maxY - newHeight; - - [infoBarView setFrame:NSMakeRect(infoBarFrame.origin.x, minY, - infoBarFrame.size.width, newHeight)]; - - NSRect contentFrame = [[self tabContentArea] frame]; - contentFrame.size.height = minY - contentFrame.origin.y; - [[self tabContentArea] setFrame:contentFrame]; -} - - (GTMTheme *)gtm_themeForWindow:(NSWindow*)window { return theme_ ? theme_ : [GTMTheme defaultTheme]; } @@ -875,60 +879,6 @@ willPositionSheet:(NSWindow*)sheet @implementation BrowserWindowController (Private) -// TODO(rohitrao, jrg): Move this logic out of BrowserWindowController? -- (void)positionInfoBar { - NSView* infoBarView = [infoBarContainerController_ view]; - NSRect infoBarFrame = [[self tabContentArea] frame]; - infoBarFrame.origin.y = NSMaxY(infoBarFrame); - infoBarFrame.size.height = 0; - [infoBarView setFrame:infoBarFrame]; - [[[self window] contentView] addSubview:infoBarView]; -} - -// If |add| is YES: -// Position |barView| below the tab strip, but not as a sibling. The -// toolbar or titlebar is part of the window's contentView, mainly -// because we want the opacity during drags to be the same as the web -// content. This can be used for either the initial add or a -// reposition. -// If |add| is NO: -// Remove the toolbar or titlebar from it's parent view (the window's -// content view). Called when going fullscreen and we need to -// minimize UI. -- (void)positionOrRemoveBar:(BOOL)add { - NSView* barView = [toolbarController_ view]; - NSRect barFrame = [barView frame]; - NSView* contentView = [self tabContentArea]; - NSRect contentFrame = [contentView frame]; - - // Shrink or grow the content area by the height of the toolbar. - if (add) - contentFrame.size.height -= barFrame.size.height; - else - contentFrame.size.height += barFrame.size.height; - [contentView setFrame:contentFrame]; - - if (add) { - // Move the toolbar above the content area, within the window's content view - // (as opposed to the tab strip, which is a sibling). - barFrame.origin.y = NSMaxY(contentFrame); - barFrame.origin.x = 0; - barFrame.size.width = contentFrame.size.width; - [barView setFrame:barFrame]; - [[[self window] contentView] addSubview:barView]; - } else { - [barView removeFromSuperview]; - } -} - -- (void)positionBar { - [self positionOrRemoveBar:YES]; -} - -- (void)removeBar { - [self positionOrRemoveBar:NO]; -} - // If the browser is in incognito mode, install the image view to decorate // the window at the upper right. Use the same base y coordinate as the // tab strip. @@ -980,14 +930,6 @@ willPositionSheet:(NSWindow*)sheet } } -- (void)tabContentAreaFrameChanged:(id)sender { - // TODO(rohitrao): This is triggered by window resizes also. Make - // sure we aren't doing anything wasteful in those cases. - [downloadShelfController_ resizeDownloadShelf]; - - [findBarCocoaController_ positionFindBarView:[self tabContentArea]]; -} - - (void)saveWindowPositionIfNeeded { if (browser_ != BrowserList::GetLastActive()) return; @@ -1081,6 +1023,68 @@ willPositionSheet:(NSWindow*)sheet [[self window] setBackgroundColor:color]; } +// Private method to layout browser window subviews. Positions the toolbar and +// the infobar above the tab content area. Positions the download shelf below +// the tab content area. If the toolbar is not a child of the contentview, this +// method will not leave room for it. If we are currently running in fullscreen +// mode, or if the tabstrip is not a descendant of the window, this method fills +// the entire content area. Otherwise, this method places the topmost view +// directly beneath the tabstrip. +- (void)layoutSubviews { + NSView* contentView = fullscreen_ ? [fullscreen_window_ contentView] + : [[self window] contentView]; + NSRect contentFrame = [contentView frame]; + int maxY = NSMaxY(contentFrame); + int minY = NSMinY(contentFrame); + if (!fullscreen_ && [self isNormalWindow]) { + maxY = NSMinY([[self tabStripView] frame]); + } + DCHECK_GE(maxY, minY); + + // Place the toolbar at the top of the reserved area, but only if we're not in + // fullscreen mode. + NSView* toolbarView = [toolbarController_ view]; + NSRect toolbarFrame = [toolbarView frame]; + if (!fullscreen_) { + // The toolbar is present in the window, so we make room for it. + toolbarFrame.origin.x = 0; + toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame); + toolbarFrame.size.width = NSWidth(contentFrame); + maxY -= NSHeight(toolbarFrame); + } + [toolbarView setFrame:toolbarFrame]; + + // Place the infobar container in place below the toolbar. + NSView* infoBarView = [infoBarContainerController_ view]; + NSRect infoBarFrame = [infoBarView frame]; + infoBarFrame.origin.y = maxY - NSHeight(infoBarFrame); + infoBarFrame.size.width = NSWidth(contentFrame); + [infoBarView setFrame:infoBarFrame]; + maxY -= NSHeight(infoBarFrame); + + // Place the download shelf at the bottom of the view, if it exists. + if (downloadShelfController_.get()) { + NSView* downloadView = [downloadShelfController_ view]; + NSRect downloadFrame = [downloadView frame]; + downloadFrame.origin.y = minY; + downloadFrame.size.width = NSWidth(contentFrame); + [downloadView setFrame:downloadFrame]; + minY += NSHeight(downloadFrame); + } + + // Finally, the tabContentArea takes up all of the remaining space. + NSView* tabContentView = [self tabContentArea]; + NSRect tabContentFrame = [tabContentView frame]; + tabContentFrame.origin.y = minY; + tabContentFrame.size.height = maxY - minY; + tabContentFrame.size.width = NSWidth(contentFrame); + [tabContentView setFrame:tabContentFrame]; + + // Position the find bar relative to the infobar container. + [findBarCocoaController_ + positionFindBarView:[infoBarContainerController_ view]]; +} + @end @implementation GTMTheme (BrowserThemeProviderInitialization) diff --git a/chrome/browser/cocoa/browser_window_controller_unittest.mm b/chrome/browser/cocoa/browser_window_controller_unittest.mm index f816a76..4b40a67 100644 --- a/chrome/browser/cocoa/browser_window_controller_unittest.mm +++ b/chrome/browser/cocoa/browser_window_controller_unittest.mm @@ -15,8 +15,26 @@ #include "chrome/test/testing_profile.h" #include "testing/gtest/include/gtest/gtest.h" -@interface BrowserWindowController (ExposedForTesting) +@interface BrowserWindowController (JustForTesting) +// Already defined in BWC. - (void)saveWindowPositionToPrefs:(PrefService*)prefs; +- (void)layoutSubviews; +@end + +@interface BrowserWindowController (ExposedForTesting) +// Implementations are below. +- (NSView*)infoBarContainerView; +- (NSView*)toolbarView; +@end + +@implementation BrowserWindowController (ExposedForTesting) +- (NSView*)infoBarContainerView { + return [infoBarContainerController_ view]; +} + +- (NSView*)toolbarView { + return [toolbarController_ view]; +} @end class BrowserWindowControllerTest : public testing::Test { @@ -52,13 +70,29 @@ TEST_F(BrowserWindowControllerTest, TestSaveWindowPosition) { } @interface BrowserWindowControllerFakeFullscreen : BrowserWindowController { + @private + // We release the window ourselves, so we don't have to rely on the unittest + // doing it for us. + scoped_nsobject<NSWindow> fullscreenWindow_; } @end @implementation BrowserWindowControllerFakeFullscreen -// This isn't needed to pass the test, but does prevent an actual -// fullscreen from happening. +// Override fullscreenWindow to return a dummy window. This isn't needed to +// pass the test, but because the dummy window is only 100x100, it prevents the +// real fullscreen window from flashing up and taking over the whole screen.. +// We have to return an actual window because layoutSubviews: looks at the +// window's frame. - (NSWindow*)fullscreenWindow { - return nil; + if (fullscreenWindow_.get()) + return fullscreenWindow_.get(); + + fullscreenWindow_.reset( + [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,400,400) + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]); + [fullscreenWindow_ setReleasedWhenClosed:NO]; + return fullscreenWindow_.get(); } @end @@ -132,4 +166,95 @@ TEST_F(BrowserWindowControllerTest, TestIncognitoWidthSpace) { } #endif +@interface BrowserWindowControllerResizePong : BrowserWindowController { +} +@end + +@implementation BrowserWindowControllerResizePong +@end + +// Test to make sure resizing and relaying-out subviews works correctly. +TEST_F(BrowserWindowControllerTest, TestResizeViews) { + TabStripView* tabstrip = [controller_ tabStripView]; + NSView* contentView = [[tabstrip window] contentView]; + NSView* toolbar = [controller_ toolbarView]; + NSView* infobar = [controller_ infoBarContainerView]; + NSView* contentArea = [controller_ tabContentArea]; + + // We need to muck with the views a bit to put us in a consistent state before + // we start resizing. In particular, we need to move the tab strip to be + // immediately above the content area, since we layout views to be directly + // under the tab strip. We also explicitly set the contentView's frame to be + // 800x600. + [contentView setFrame:NSMakeRect(0, 0, 800, 600)]; + NSRect tabstripFrame = [tabstrip frame]; + tabstripFrame.origin.y = NSMaxY([contentView frame]); + [tabstrip setFrame:tabstripFrame]; + + // Make sure each view is as tall as we expect. + ASSERT_EQ(39, NSHeight([toolbar frame])); + ASSERT_EQ(0, NSHeight([infobar frame])); + + // Force a layout and check each view's frame. + // contentView should be at 0,0 800x600 + // contentArea should be at 0,0 800x561 + // infobar should be at 0,561 800x0 + // toolbar should be at 0,561 800x39 + [controller_ layoutSubviews]; + EXPECT_TRUE(NSEqualRects([contentView frame], NSMakeRect(0, 0, 800, 600))); + EXPECT_TRUE(NSEqualRects([contentArea frame], NSMakeRect(0, 0, 800, 561))); + EXPECT_TRUE(NSEqualRects([infobar frame], NSMakeRect(0, 561, 800, 0))); + EXPECT_TRUE(NSEqualRects([toolbar frame], NSMakeRect(0, 561, 800, 39))); + + // Expand the infobar to 60px and recheck + // contentView should be at 0,0 800x600 + // contentArea should be at 0,0 800x501 + // infobar should be at 0,501 800x60 + // toolbar should be at 0,561 800x39 + [controller_ resizeView:infobar newHeight:60]; + EXPECT_TRUE(NSEqualRects([contentView frame], NSMakeRect(0, 0, 800, 600))); + EXPECT_TRUE(NSEqualRects([contentArea frame], NSMakeRect(0, 0, 800, 501))); + EXPECT_TRUE(NSEqualRects([infobar frame], NSMakeRect(0, 501, 800, 60))); + EXPECT_TRUE(NSEqualRects([toolbar frame], NSMakeRect(0, 561, 800, 39))); + + // Expand the toolbar to 64px and recheck + // contentView should be at 0,0 800x600 + // contentArea should be at 0,0 800x476 + // infobar should be at 0,476 800x60 + // toolbar should be at 0,536 800x64 + [controller_ resizeView:toolbar newHeight:64]; + EXPECT_TRUE(NSEqualRects([contentView frame], NSMakeRect(0, 0, 800, 600))); + EXPECT_TRUE(NSEqualRects([contentArea frame], NSMakeRect(0, 0, 800, 476))); + EXPECT_TRUE(NSEqualRects([infobar frame], NSMakeRect(0, 476, 800, 60))); + EXPECT_TRUE(NSEqualRects([toolbar frame], NSMakeRect(0, 536, 800, 64))); + + // Add a 30px download shelf and recheck + // contentView should be at 0,0 800x600 + // download should be at 0,0 800x30 + // contentArea should be at 0,30 800x446 + // infobar should be at 0,476 800x60 + // toolbar should be at 0,536 800x64 + NSView* download = [[controller_ downloadShelf] view]; + [controller_ resizeView:download newHeight:30]; + EXPECT_TRUE(NSEqualRects([contentView frame], NSMakeRect(0, 0, 800, 600))); + EXPECT_TRUE(NSEqualRects([download frame], NSMakeRect(0, 0, 800, 30))); + EXPECT_TRUE(NSEqualRects([contentArea frame], NSMakeRect(0, 30, 800, 446))); + EXPECT_TRUE(NSEqualRects([infobar frame], NSMakeRect(0, 476, 800, 60))); + EXPECT_TRUE(NSEqualRects([toolbar frame], NSMakeRect(0, 536, 800, 64))); + + // Shrink the infobar to 0px and toolbar to 39px and recheck + // contentView should be at 0,0 800x600 + // download should be at 0,0 800x30 + // contentArea should be at 0,30 800x531 + // infobar should be at 0,561 800x0 + // toolbar should be at 0,561 800x39 + [controller_ resizeView:infobar newHeight:0]; + [controller_ resizeView:toolbar newHeight:39]; + EXPECT_TRUE(NSEqualRects([contentView frame], NSMakeRect(0, 0, 800, 600))); + EXPECT_TRUE(NSEqualRects([download frame], NSMakeRect(0, 0, 800, 30))); + EXPECT_TRUE(NSEqualRects([contentArea frame], NSMakeRect(0, 30, 800, 531))); + EXPECT_TRUE(NSEqualRects([infobar frame], NSMakeRect(0, 561, 800, 0))); + EXPECT_TRUE(NSEqualRects([toolbar frame], NSMakeRect(0, 561, 800, 39))); +} + /* TODO(???): test other methods of BrowserWindowController */ diff --git a/chrome/browser/cocoa/download_shelf_controller.h b/chrome/browser/cocoa/download_shelf_controller.h index c72538a..9ace0d3 100644 --- a/chrome/browser/cocoa/download_shelf_controller.h +++ b/chrome/browser/cocoa/download_shelf_controller.h @@ -6,6 +6,7 @@ #include "base/scoped_nsobject.h" #include "base/scoped_ptr.h" +#import "chrome/browser/cocoa/view_resizer.h" class BaseDownloadItemModel; class Browser; @@ -38,14 +39,9 @@ class DownloadShelf; IBOutlet NSImageView* image_; - // Currently these two are always the same, but they mean slightly different - // things. |contentAreaHasOffset_| is an implementation detail of the download - // shelf visibility. - BOOL contentAreaHasOffset_; BOOL barIsVisible_; scoped_ptr<DownloadShelf> bridge_; - NSView* contentArea_; // the browser's content area float shelfHeight_; // The download items we have added to our shelf. @@ -53,9 +49,13 @@ class DownloadShelf; // The container that contains (and clamps) all the download items. IBOutlet NSView* itemContainerView_; + + // Delegate that handles resizing our view. + id<ViewResizer> resizeDelegate_; }; -- (id)initWithBrowser:(Browser*)browser contentArea:(NSView*)content; +- (id)initWithBrowser:(Browser*)browser + resizeDelegate:(id<ViewResizer>)resizeDelegate; - (DownloadShelf*)bridge; - (BOOL)isVisible; @@ -67,9 +67,6 @@ class DownloadShelf; - (void)addDownloadItem:(BaseDownloadItemModel*)model; -// Resizes the download shelf based on the state of the content area. -- (void)resizeDownloadShelf; - // Remove a download, possibly via clearing browser data. - (void)remove:(DownloadItemController*)download; diff --git a/chrome/browser/cocoa/download_shelf_controller.mm b/chrome/browser/cocoa/download_shelf_controller.mm index 0cb170a..8a63da9 100644 --- a/chrome/browser/cocoa/download_shelf_controller.mm +++ b/chrome/browser/cocoa/download_shelf_controller.mm @@ -40,7 +40,6 @@ const NSTimeInterval kDownloadItemOpenDuration = 0.8; @interface DownloadShelfController(Private) - (void)applyContentAreaOffset:(BOOL)apply; -- (void)positionBar; - (void)showDownloadShelf:(BOOL)enable; - (void)resizeDownloadLinkToFit; @end @@ -49,14 +48,15 @@ const NSTimeInterval kDownloadItemOpenDuration = 0.8; @implementation DownloadShelfController - (id)initWithBrowser:(Browser*)browser - contentArea:(NSView*)content { + resizeDelegate:(id<ViewResizer>)resizeDelegate { if ((self = [super initWithNibName:@"DownloadShelf" bundle:mac_util::MainAppBundle()])) { - contentArea_ = content; + resizeDelegate_ = resizeDelegate; shelfHeight_ = [[self view] bounds].size.height; - [self positionBar]; - [[[contentArea_ window] contentView] addSubview:[self view]]; + // Reset the download shelf's frame to zero. It will be properly positioned + // and sized the first time we try to set its height. + [[self view] setFrame:NSZeroRect]; downloadItemControllers_.reset([[NSMutableArray alloc] init]); @@ -136,26 +136,6 @@ const NSTimeInterval kDownloadItemOpenDuration = 0.8; return YES; } -// Initializes the download shelf at the bottom edge of |contentArea_|. -- (void)positionBar { - // Set the bar's height to zero and position it at the bottom of the content - // area, within the window's content view (as opposed to the tab strip, which - // is a sibling). We'll enlarge it and slide the content area up when we need - // to show this strip. - NSRect contentFrame = [contentArea_ frame]; - NSRect barFrame = NSMakeRect(0, 0, contentFrame.size.width, shelfHeight_); - [[self view] setFrame:barFrame]; -} - -// Called when the contentArea's frame changes. Enlarge the view to stay with -// the bottom of the contentArea. -- (void)resizeDownloadShelf { - NSRect barFrame = [[self view] frame]; - barFrame.origin.y = 0; - barFrame.size.height = NSMinY([contentArea_ frame]); - [[self view] setFrame:barFrame]; -} - - (void)remove:(DownloadItemController*)download { // Look for the download in our controller array and remove it. This will // explicity release it so that it removes itself as an Observer of the @@ -185,36 +165,11 @@ const NSTimeInterval kDownloadItemOpenDuration = 0.8; if ([self isVisible] == enable) return; - contentAreaHasOffset_ = enable; - [[self view] setHidden:enable ? NO : YES]; - [self applyContentAreaOffset:enable]; - + [resizeDelegate_ resizeView:[self view] + newHeight:(enable ? shelfHeight_ : 0)]; barIsVisible_ = enable; } -// Apply a contents box offset to make (or remove) room for the download shelf. -// If apply is YES, always make room (the contentView_ is "full size"). If apply -// is NO, we are trying to undo an offset. If no offset there is nothing to undo. -- (void)applyContentAreaOffset:(BOOL)apply { - if (!contentAreaHasOffset_ && apply) { - // There is no offset to unconditionally apply. - return; - } - - NSRect frame = [contentArea_ frame]; - if (apply) { - frame.origin.y += shelfHeight_; - frame.size.height -= shelfHeight_; - } else { - frame.origin.y -= shelfHeight_; - frame.size.height += shelfHeight_; - } - - [[contentArea_ animator] setFrame:frame]; - [[self view] setNeedsDisplay:YES]; - [contentArea_ setNeedsDisplay:YES]; -} - - (DownloadShelf*)bridge { return bridge_.get(); } diff --git a/chrome/browser/cocoa/download_shelf_mac.mm b/chrome/browser/cocoa/download_shelf_mac.mm index c415dc3..159ea06 100644 --- a/chrome/browser/cocoa/download_shelf_mac.mm +++ b/chrome/browser/cocoa/download_shelf_mac.mm @@ -13,7 +13,6 @@ DownloadShelfMac::DownloadShelfMac(Browser* browser, DownloadShelfController* controller) : browser_(browser), shelf_controller_(controller) { - Show(); } void DownloadShelfMac::AddDownload(BaseDownloadItemModel* download_model) { diff --git a/chrome/browser/cocoa/download_shelf_mac_unittest.mm b/chrome/browser/cocoa/download_shelf_mac_unittest.mm index 78ff52d..1df20e3 100644 --- a/chrome/browser/cocoa/download_shelf_mac_unittest.mm +++ b/chrome/browser/cocoa/download_shelf_mac_unittest.mm @@ -57,19 +57,19 @@ class DownloadShelfMacTest : public testing::Test { BrowserTestHelper browser_helper_; }; -TEST_F(DownloadShelfMacTest, CreationCallsShow) { +TEST_F(DownloadShelfMacTest, CreationDoesNotCallShow) { // Also make sure the DownloadShelfMacTest constructor doesn't crash. DownloadShelfMac shelf(browser_helper_.browser(), (DownloadShelfController*)shelf_controller_.get()); - EXPECT_EQ(1, shelf_controller_.get()->callCountShow); + EXPECT_EQ(0, shelf_controller_.get()->callCountShow); } TEST_F(DownloadShelfMacTest, ForwardsShow) { DownloadShelfMac shelf(browser_helper_.browser(), (DownloadShelfController*)shelf_controller_.get()); - EXPECT_EQ(1, shelf_controller_.get()->callCountShow); + EXPECT_EQ(0, shelf_controller_.get()->callCountShow); shelf.Show(); - EXPECT_EQ(2, shelf_controller_.get()->callCountShow); + EXPECT_EQ(1, shelf_controller_.get()->callCountShow); } TEST_F(DownloadShelfMacTest, ForwardsHide) { diff --git a/chrome/browser/cocoa/find_bar_cocoa_controller.h b/chrome/browser/cocoa/find_bar_cocoa_controller.h index 933f88e..13837de 100644 --- a/chrome/browser/cocoa/find_bar_cocoa_controller.h +++ b/chrome/browser/cocoa/find_bar_cocoa_controller.h @@ -40,8 +40,9 @@ class FindNotificationDetails; - (IBAction)previousResult:(id)sender; -// Positions the find bar based on the location of |contentArea|. -- (void)positionFindBarView:(NSView*)contentArea; +// Positions the find bar based on the location of the infobar container. +// TODO(rohitrao): Move this logic into BrowserWindowController. +- (void)positionFindBarView:(NSView*)infoBarContainerView; // Methods called from FindBarBridge. - (void)showFindBar; diff --git a/chrome/browser/cocoa/find_bar_cocoa_controller.mm b/chrome/browser/cocoa/find_bar_cocoa_controller.mm index f28fd56..15b53d6 100644 --- a/chrome/browser/cocoa/find_bar_cocoa_controller.mm +++ b/chrome/browser/cocoa/find_bar_cocoa_controller.mm @@ -52,21 +52,23 @@ true, false); } -// Positions the find bar view in the correct location based on the -// current state of the window. Currently only the visibility of the -// bookmark bar can affect the find bar's position. -- (void)positionFindBarView:(NSView*)contentArea { +// Positions the find bar view in the correct location based on the current +// state of the window. The findbar is always positioned one pixel above the +// infobar container. Note that we are using the infobar container location as +// a proxy for the toolbar location, but we cannot position based on the toolbar +// because the toolbar is not always present (for example in fullscreen +// windows). +- (void)positionFindBarView:(NSView*)infoBarContainerView { static const int kRightEdgeOffset = 25; NSView* findBarView = [self view]; int findBarHeight = NSHeight([findBarView frame]); int findBarWidth = NSWidth([findBarView frame]); - // Start by computing the upper right corner of the tab content - // area, then move left by a constant offset and up one pixel. This - // gives us the upper right corner of our bounding box. We move up - // one pixel to overlap with the toolbar area, which allows us to - // cover up the toolbar's border. - NSRect windowRect = [contentArea frame]; + // Start by computing the upper right corner of the infobar container, then + // move left by a constant offset and up one pixel. This gives us the upper + // right corner of our bounding box. We move up one pixel to overlap with the + // toolbar area, which allows us to cover up the toolbar's border, if present. + NSRect windowRect = [infoBarContainerView frame]; int max_x = NSMaxX(windowRect) - kRightEdgeOffset; int max_y = NSMaxY(windowRect) + 1; diff --git a/chrome/browser/cocoa/infobar_container_controller.h b/chrome/browser/cocoa/infobar_container_controller.h index a565a10..cfd7157 100644 --- a/chrome/browser/cocoa/infobar_container_controller.h +++ b/chrome/browser/cocoa/infobar_container_controller.h @@ -6,9 +6,9 @@ #include "base/scoped_nsobject.h" #include "base/scoped_ptr.h" +#import "chrome/browser/cocoa/view_resizer.h" #include "chrome/common/notification_registrar.h" -@class BrowserWindowController; class InfoBarDelegate; class InfoBarNotificationObserver; class TabContents; @@ -22,8 +22,8 @@ class TabStripModelObserverBridge; // adding/removing infobars when needed. @interface InfoBarContainerController : NSViewController { @private - // Needed to send infoBarResized: messages when infobars are added or removed. - BrowserWindowController* browserController_; // weak, owns us. + // Needed to send resize messages when infobars are added or removed. + id<ViewResizer> resizeDelegate_; // weak // The TabContents we are currently showing infobars for. TabContents* currentTabContents_; // weak @@ -42,7 +42,7 @@ class TabStripModelObserverBridge; } - (id)initWithTabStripModel:(TabStripModel*)model - browserWindowController:(BrowserWindowController*)controller; + resizeDelegate:(id<ViewResizer>)resizeDelegate; // Informs the selected TabContents that the infobars for the given // |delegate| need to be removed. Does not remove any infobar views diff --git a/chrome/browser/cocoa/infobar_container_controller.mm b/chrome/browser/cocoa/infobar_container_controller.mm index 06eaf67..4acc324 100644 --- a/chrome/browser/cocoa/infobar_container_controller.mm +++ b/chrome/browser/cocoa/infobar_container_controller.mm @@ -4,7 +4,6 @@ #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" @@ -64,11 +63,11 @@ class InfoBarNotificationObserver : public NotificationObserver { @implementation InfoBarContainerController - (id)initWithTabStripModel:(TabStripModel*)model - browserWindowController:(BrowserWindowController*)controller { - DCHECK(controller); + resizeDelegate:(id<ViewResizer>)resizeDelegate { + DCHECK(resizeDelegate); if ((self = [super initWithNibName:@"InfoBarContainer" bundle:mac_util::MainAppBundle()])) { - browserController_ = controller; + resizeDelegate_ = resizeDelegate; tabObserver_.reset(new TabStripModelObserverBridge(model, self)); infoBarObserver_.reset(new InfoBarNotificationObserver(self)); @@ -185,7 +184,7 @@ class InfoBarNotificationObserver : public NotificationObserver { [view setFrame:frame]; } - [browserController_ infoBarResized:[self desiredHeight]]; + [resizeDelegate_ resizeView:[self view] newHeight:[self desiredHeight]]; } @end diff --git a/chrome/browser/cocoa/infobar_container_controller_unittest.mm b/chrome/browser/cocoa/infobar_container_controller_unittest.mm index 77e8e82..b50e7d4 100644 --- a/chrome/browser/cocoa/infobar_container_controller_unittest.mm +++ b/chrome/browser/cocoa/infobar_container_controller_unittest.mm @@ -7,44 +7,21 @@ #include "base/scoped_nsautorelease_pool.h" #include "base/scoped_nsobject.h" #include "chrome/browser/cocoa/browser_test_helper.h" -#import "chrome/browser/cocoa/browser_window_controller.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" #import "chrome/browser/cocoa/infobar_container_controller.h" #include "chrome/browser/cocoa/infobar_test_helper.h" +#import "chrome/browser/cocoa/view_resizer_pong.h" #include "testing/gtest/include/gtest/gtest.h" -// Objective-C classes must be defined outside the namespace. -@interface BrowserWindowControllerPong : BrowserWindowController { - BOOL pong_; -} -@property(readonly) BOOL pong; -@end - -@implementation BrowserWindowControllerPong -@synthesize pong = pong_; - -- (id)initWithBrowser:(Browser*)browser { - if ((self = [super initWithBrowser:browser takeOwnership:NO])) { - pong_ = NO; - } - return self; -} - -- (void)infoBarResized:(float)newHeight { - pong_ = TRUE; -} -@end - namespace { class InfoBarContainerControllerTest : public testing::Test { virtual void SetUp() { - browserController_.reset([[BrowserWindowControllerPong alloc] - initWithBrowser:browser_helper_.browser()]); + resizeDelegate_.reset([[ViewResizerPong alloc] init]); TabStripModel* model = browser_helper_.browser()->tabstrip_model(); controller_.reset([[InfoBarContainerController alloc] initWithTabStripModel:model - browserWindowController:browserController_]); + resizeDelegate:resizeDelegate_.get()]); } public: @@ -54,7 +31,7 @@ class InfoBarContainerControllerTest : public testing::Test { CocoaTestHelper cocoa_helper_; BrowserTestHelper browser_helper_; base::ScopedNSAutoreleasePool pool_; - scoped_nsobject<BrowserWindowControllerPong> browserController_; + scoped_nsobject<ViewResizerPong> resizeDelegate_; scoped_nsobject<InfoBarContainerController> controller_; }; @@ -67,9 +44,11 @@ TEST_F(InfoBarContainerControllerTest, Show) { } TEST_F(InfoBarContainerControllerTest, BWCPong) { - // Call positionInfoBarsAndResize and check that the BWC got a resize message. + // Call positionInfoBarsAndResize and check that |resizeDelegate_| got a + // resize message. + [resizeDelegate_ setHeight:-1]; [controller_ positionInfoBarsAndRedraw]; - EXPECT_TRUE([browserController_ pong]); + EXPECT_NE(-1, [resizeDelegate_ height]); } TEST_F(InfoBarContainerControllerTest, AddAndRemoveInfoBars) { diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h index 07ec3e7..0e33048 100644 --- a/chrome/browser/cocoa/toolbar_controller.h +++ b/chrome/browser/cocoa/toolbar_controller.h @@ -11,6 +11,7 @@ #include "base/scoped_nsobject.h" #import "chrome/browser/cocoa/command_observer_bridge.h" #import "chrome/browser/cocoa/bookmark_bar_controller.h" +#import "chrome/browser/cocoa/view_resizer.h" #include "chrome/common/pref_member.h" @class AutocompleteTextField; @@ -31,7 +32,8 @@ class ToolbarView; // Manages the bookmark bar and it's position in the window relative to // the web content view. -@interface ToolbarController : NSViewController<CommandObserverProtocol> { +@interface ToolbarController : + NSViewController<CommandObserverProtocol, ViewResizer> { @private ToolbarModel* toolbarModel_; // weak, one per window CommandUpdater* commands_; // weak, one per window @@ -40,9 +42,8 @@ class ToolbarView; scoped_ptr<LocationBarViewMac> locationBarView_; scoped_nsobject<AutocompleteTextFieldEditor> autocompleteTextFieldEditor_; scoped_nsobject<BookmarkBarController> bookmarkBarController_; + id<ViewResizer> resizeDelegate_; // weak id<BookmarkURLOpener> bookmarkBarDelegate_; // weak - NSView* webContentView_; // weak; where the web goes - NSView* infoBarsView_; // weak; where the infobars go // Used for monitoring the optional toolbar button prefs. scoped_ptr<ToolbarControllerInternal::PrefObserverBridge> prefObserver_; @@ -76,8 +77,7 @@ class ToolbarView; - (id)initWithModel:(ToolbarModel*)model commands:(CommandUpdater*)commands profile:(Profile*)profile - webContentView:(NSView*)webContentView - infoBarsView:(NSView*)infoBarsView + resizeDelegate:(id<ViewResizer>)resizeDelegate bookmarkDelegate:(id<BookmarkURLOpener>)delegate; // Get the C++ bridge object representing the location bar for this tab. diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm index b5bc147..c999764 100644 --- a/chrome/browser/cocoa/toolbar_controller.mm +++ b/chrome/browser/cocoa/toolbar_controller.mm @@ -23,6 +23,12 @@ // Name of image in the bundle for the yellow of the star icon. static NSString* const kStarredImageName = @"starred.pdf"; +// Height of the toolbar in pixels when the bookmark bar is closed. +static const float kBaseToolbarHeight = 39.0; + +// Overlap (in pixels) between the toolbar and the bookmark bar. +static const float kBookmarkBarOverlap = 5.0; + @interface ToolbarController(Private) - (void)initCommandStatus:(CommandUpdater*)commands; - (void)prefChanged:(std::wstring*)prefName; @@ -54,8 +60,7 @@ class PrefObserverBridge : public NotificationObserver { - (id)initWithModel:(ToolbarModel*)model commands:(CommandUpdater*)commands profile:(Profile*)profile - webContentView:(NSView*)webContentView - infoBarsView:(NSView*)infoBarsView + resizeDelegate:(id<ViewResizer>)resizeDelegate bookmarkDelegate:(id<BookmarkURLOpener>)delegate { DCHECK(model && commands && profile); if ((self = [super initWithNibName:@"Toolbar" @@ -63,9 +68,8 @@ class PrefObserverBridge : public NotificationObserver { toolbarModel_ = model; commands_ = commands; profile_ = profile; + resizeDelegate_ = resizeDelegate; bookmarkBarDelegate_ = delegate; - webContentView_ = webContentView; - infoBarsView_ = infoBarsView; hasToolbar_ = YES; // Register for notifications about state changes for the toolbar buttons @@ -109,10 +113,9 @@ class PrefObserverBridge : public NotificationObserver { // Create a sub-controller for the bookmark bar. bookmarkBarController_.reset([[BookmarkBarController alloc] initWithProfile:profile_ - parentView:[self view] - webContentView:webContentView_ - infoBarsView:infoBarsView_ - delegate:bookmarkBarDelegate_]); + initialWidth:NSWidth([[self view] frame]) + resizeDelegate:self + urlDelegate:bookmarkBarDelegate_]); // Add bookmark bar to the view hierarchy. This also triggers the // nib load. The bookmark bar is defined (in the nib) to be @@ -131,6 +134,22 @@ class PrefObserverBridge : public NotificationObserver { locationBarRetainer_.reset([locationBar_ retain]); } +- (void)resizeView:(NSView*)view newHeight:(float)height { + DCHECK(view == [bookmarkBarController_ view]); + + // The bookmark bar is always rooted at the bottom of the toolbar view, with + // width equal to the toolbar's width. The toolbar view is resized to + // accomodate the new bookmark bar height. + NSRect frame = NSMakeRect(0, 0, [[self view] bounds].size.width, height); + [view setFrame:frame]; + + float newToolbarHeight = kBaseToolbarHeight + height - kBookmarkBarOverlap; + if (newToolbarHeight < kBaseToolbarHeight) + newToolbarHeight = kBaseToolbarHeight; + + [resizeDelegate_ resizeView:[self view] newHeight:newToolbarHeight]; +} + - (LocationBar*)locationBar { return locationBarView_.get(); } diff --git a/chrome/browser/cocoa/toolbar_controller_unittest.mm b/chrome/browser/cocoa/toolbar_controller_unittest.mm index 9690c5b..a82212b 100644 --- a/chrome/browser/cocoa/toolbar_controller_unittest.mm +++ b/chrome/browser/cocoa/toolbar_controller_unittest.mm @@ -9,6 +9,7 @@ #include "chrome/browser/cocoa/browser_test_helper.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" #import "chrome/browser/cocoa/toolbar_controller.h" +#import "chrome/browser/cocoa/view_resizer_pong.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" #include "testing/gtest/include/gtest/gtest.h" @@ -32,12 +33,12 @@ class ToolbarControllerTest : public testing::Test { // ensure they get picked up correct on initialization updater->UpdateCommandEnabled(IDC_BACK, false); updater->UpdateCommandEnabled(IDC_FORWARD, false); + resizeDelegate_.reset([[ViewResizerPong alloc] init]); bar_.reset( [[ToolbarController alloc] initWithModel:browser->toolbar_model() commands:browser->command_updater() profile:helper_.profile() - webContentView:nil - infoBarsView:nil + resizeDelegate:resizeDelegate_.get() bookmarkDelegate:nil]); EXPECT_TRUE([bar_ view]); NSView* parent = [cocoa_helper_.window() contentView]; @@ -61,6 +62,7 @@ class ToolbarControllerTest : public testing::Test { CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... BrowserTestHelper helper_; + scoped_nsobject<ViewResizerPong> resizeDelegate_; scoped_nsobject<ToolbarController> bar_; }; @@ -192,4 +194,32 @@ TEST_F(ToolbarControllerTest, TogglePageWrench) { EXPECT_NE(NSWidth(originalLocationBarFrame), NSWidth([locationBar frame])); } +TEST_F(ToolbarControllerTest, BookmarkBarResizes) { + NSView* bookmarkBarView = [[bar_ bookmarkBarController] view]; + ASSERT_EQ(0, NSHeight([bookmarkBarView frame])); + [resizeDelegate_ setHeight:-1]; + + // Resize the bookmarkbar to 30px. The toolbar should ask the delegate to + // resize to 64px. + [bar_ resizeView:bookmarkBarView newHeight:30]; + EXPECT_EQ(64, [resizeDelegate_ height]); + EXPECT_EQ(30, NSHeight([bookmarkBarView frame])); + + // Resize the bookmarkbar back to 0px. Toolbar should be at 39px. + [bar_ resizeView:bookmarkBarView newHeight:0]; + EXPECT_EQ(39, [resizeDelegate_ height]); + EXPECT_EQ(0, NSHeight([bookmarkBarView frame])); + + // Resize the bookmarkbar to 5px. Toolbar should stay at 39px. + [resizeDelegate_ setHeight:-1]; + [bar_ resizeView:bookmarkBarView newHeight:5]; + EXPECT_EQ(39, [resizeDelegate_ height]); + EXPECT_EQ(5, NSHeight([bookmarkBarView frame])); + + // Resize the bookmarkbar to 6px. Toolbar should grow to 40px. + [bar_ resizeView:bookmarkBarView newHeight:6]; + EXPECT_EQ(40, [resizeDelegate_ height]); + EXPECT_EQ(6, NSHeight([bookmarkBarView frame])); +} + } // namespace diff --git a/chrome/browser/cocoa/view_resizer.h b/chrome/browser/cocoa/view_resizer.h new file mode 100644 index 0000000..199b60f --- /dev/null +++ b/chrome/browser/cocoa/view_resizer.h @@ -0,0 +1,21 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_VIEW_RESIZER_H_ +#define CHROME_BROWSER_COCOA_VIEW_RESIZER_H_ + +#include "chrome/browser/tabs/tab_strip_model.h" + +#import <Cocoa/Cocoa.h> + +// Defines a protocol that allows controllers to delegate resizing their views +// to their parents. When a controller needs to change a view's height, rather +// than resizing it directly, it sends a message to its parent asking the parent +// to perform the resize. This allows the parent to do any re-layout that may +// become necessary due to the resize. +@protocol ViewResizer +- (void)resizeView:(NSView*)view newHeight:(float)height; +@end + +#endif // CHROME_BROWSER_COCOA_VIEW_RESIZER_H_ diff --git a/chrome/browser/cocoa/view_resizer_pong.h b/chrome/browser/cocoa/view_resizer_pong.h new file mode 100644 index 0000000..0f3caf2 --- /dev/null +++ b/chrome/browser/cocoa/view_resizer_pong.h @@ -0,0 +1,21 @@ +// 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. + +#ifndef CHROME_BROWSER_COCOA_VIEW_RESIZER_PONG_H_ +#define CHROME_BROWSER_COCOA_VIEW_RESIZER_PONG_H_ + +#import <Cocoa/Cocoa.h> + +#import "chrome/browser/cocoa/view_resizer.h" + +@interface ViewResizerPong : NSObject<ViewResizer> { + @private + float height_; +} +@property float height; + +- (void)resizeView:(NSView*)view newHeight:(float)height; +@end + +#endif // CHROME_BROWSER_COCOA_VIEW_RESIZER_PONG_H_ diff --git a/chrome/browser/cocoa/view_resizer_pong.mm b/chrome/browser/cocoa/view_resizer_pong.mm new file mode 100644 index 0000000..9246af7 --- /dev/null +++ b/chrome/browser/cocoa/view_resizer_pong.mm @@ -0,0 +1,19 @@ +// 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. + +#import <Cocoa/Cocoa.h> + +#import "chrome/browser/cocoa/view_resizer_pong.h" + +@implementation ViewResizerPong + +@synthesize height = height_; + +- (void)resizeView:(NSView*)view newHeight:(float)height { + [self setHeight:height]; + + // Set the view's height and width, in case it uses that as important state. + [view setFrame:NSMakeRect(100, 100, 250, height)]; +} +@end diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 06eab55..c2eb3ea 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -876,6 +876,7 @@ 'browser/cocoa/toolbar_view.mm', 'browser/cocoa/ui_localizer.h', 'browser/cocoa/ui_localizer.mm', + 'browser/cocoa/view_resizer.h', 'browser/cocoa/web_drag_source.h', 'browser/cocoa/web_drag_source.mm', 'browser/cocoa/web_drop_target.h', @@ -3711,6 +3712,8 @@ 'browser/cocoa/toolbar_controller_unittest.mm', 'browser/cocoa/toolbar_view_unittest.mm', 'browser/cocoa/ui_localizer_unittest.mm', + 'browser/cocoa/view_resizer_pong.h', + 'browser/cocoa/view_resizer_pong.mm', 'browser/cocoa/web_drop_target_unittest.mm', 'browser/command_updater_unittest.cc', 'browser/debugger/devtools_manager_unittest.cc', |