diff options
author | rohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-07 04:49:14 +0000 |
---|---|---|
committer | rohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-07 04:49:14 +0000 |
commit | 7b0ec59003697f626184af266d670b014c5715d5 (patch) | |
tree | 1c4864c9268e1cec9c7c83d328db3bb323fb92c9 /chrome | |
parent | c1d10a389f07e7cf1274cb4c053e5cee0bda095a (diff) | |
download | chromium_src-7b0ec59003697f626184af266d670b014c5715d5.zip chromium_src-7b0ec59003697f626184af266d670b014c5715d5.tar.gz chromium_src-7b0ec59003697f626184af266d670b014c5715d5.tar.bz2 |
Reverts the revert of 22517.
Rewrites the Mac view resizing logic to have the BrowserWindowController
directly resize and relayout its children views. Now when a view needs
to be resized, it asks its resize delegate (typically its controller's
parent) to perform the resize.
BUG=http://crbug.com/17619
TEST=Make sure that views are laid out correctly, even when they change size.
Open and close the bookmark bar. Trigger an infobar and then close it. Trigger
the download shelf and then close it. Trigger a download shelf with the infobar
open, or with the bookmark bar open. Switch to and from fullscreen with various
bars open. Resize the browser window with various bars open. Start the browser
with and without the bookmark bar open. Try all of the above in a popup window.
Review URL: http://codereview.chromium.org/165014
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22721 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
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', |