| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/cocoa/bookmark_bar_folder_controller.h" | 5 #import "chrome/browser/cocoa/bookmark_bar_folder_controller.h" |
| 6 #include "base/mac_util.h" | 6 #include "base/mac_util.h" |
| 7 #include "base/nsimage_cache_mac.h" | 7 #include "base/nsimage_cache_mac.h" |
| 8 #include "base/sys_string_conversions.h" | 8 #include "base/sys_string_conversions.h" |
| 9 #include "chrome/browser/bookmarks/bookmark_model.h" | 9 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 10 #include "chrome/browser/bookmarks/bookmark_utils.h" | 10 #include "chrome/browser/bookmarks/bookmark_utils.h" |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 - (void)toggleButtonBorderingWhileMouseInside { | 98 - (void)toggleButtonBorderingWhileMouseInside { |
| 99 BOOL toggle = [self showsBorderOnlyWhileMouseInside]; | 99 BOOL toggle = [self showsBorderOnlyWhileMouseInside]; |
| 100 [self setShowsBorderOnlyWhileMouseInside:!toggle]; | 100 [self setShowsBorderOnlyWhileMouseInside:!toggle]; |
| 101 [self setShowsBorderOnlyWhileMouseInside:toggle]; | 101 [self setShowsBorderOnlyWhileMouseInside:toggle]; |
| 102 } | 102 } |
| 103 | 103 |
| 104 @end | 104 @end |
| 105 | 105 |
| 106 @implementation BookmarkBarFolderController | 106 @implementation BookmarkBarFolderController |
| 107 | 107 |
| 108 @synthesize subFolderGrowthToRight = subFolderGrowthToRight_; |
| 109 |
| 108 - (id)initWithParentButton:(BookmarkButton*)button | 110 - (id)initWithParentButton:(BookmarkButton*)button |
| 109 parentController:(BookmarkBarFolderController*)parentController | 111 parentController:(BookmarkBarFolderController*)parentController |
| 110 barController:(BookmarkBarController*)barController { | 112 barController:(BookmarkBarController*)barController { |
| 111 NSString* nibPath = | 113 NSString* nibPath = |
| 112 [mac_util::MainAppBundle() pathForResource:@"BookmarkBarFolderWindow" | 114 [mac_util::MainAppBundle() pathForResource:@"BookmarkBarFolderWindow" |
| 113 ofType:@"nib"]; | 115 ofType:@"nib"]; |
| 114 if ((self = [super initWithWindowNibPath:nibPath owner:self])) { | 116 if ((self = [super initWithWindowNibPath:nibPath owner:self])) { |
| 115 parentButton_.reset([button retain]); | 117 parentButton_.reset([button retain]); |
| 116 | 118 |
| 117 // We want the button to remain bordered as part of the menu path. | 119 // We want the button to remain bordered as part of the menu path. |
| 118 [button forceButtonBorderToStayOnAlways:YES]; | 120 [button forceButtonBorderToStayOnAlways:YES]; |
| 119 | 121 |
| 120 parentController_.reset([parentController retain]); | 122 parentController_.reset([parentController retain]); |
| 123 if (!parentController_) |
| 124 [self setSubFolderGrowthToRight:YES]; |
| 125 else |
| 126 [self setSubFolderGrowthToRight:[parentController |
| 127 subFolderGrowthToRight]]; |
| 121 barController_ = barController; // WEAK | 128 barController_ = barController; // WEAK |
| 122 buttons_.reset([[NSMutableArray alloc] init]); | 129 buttons_.reset([[NSMutableArray alloc] init]); |
| 123 folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]); | 130 folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]); |
| 124 NSImage* image = nsimage_cache::ImageNamed(@"menu_overflow_up.pdf"); | 131 NSImage* image = nsimage_cache::ImageNamed(@"menu_overflow_up.pdf"); |
| 125 DCHECK(image); | 132 DCHECK(image); |
| 126 verticalScrollArrowHeight_ = [image size].height; | 133 verticalScrollArrowHeight_ = [image size].height; |
| 127 [self configureWindow]; | 134 [self configureWindow]; |
| 128 hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]); | 135 hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]); |
| 129 } | 136 } |
| 130 return self; | 137 return self; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 | 263 |
| 257 // Exposed for testing. | 264 // Exposed for testing. |
| 258 - (NSView*)mainView { | 265 - (NSView*)mainView { |
| 259 return mainView_; | 266 return mainView_; |
| 260 } | 267 } |
| 261 | 268 |
| 262 - (id)folderTarget { | 269 - (id)folderTarget { |
| 263 return folderTarget_.get(); | 270 return folderTarget_.get(); |
| 264 } | 271 } |
| 265 | 272 |
| 273 |
| 274 // Our parent controller is another BookmarkBarFolderController, so |
| 275 // our window is to the right or left of it. We use a little overlap |
| 276 // since it looks much more menu-like than with none. If we would |
| 277 // grow off the screen, switch growth to the other direction. Growth |
| 278 // direction sticks for folder windows which are descendents of us. |
| 279 // If we have tried both directions and neither fits, degrade to a |
| 280 // default. |
| 281 - (CGFloat)childFolderWindowLeftForWidth:(int)windowWidth { |
| 282 // We may legitimately need to try two times (growth to right and |
| 283 // left but not in that order). Limit us to three tries in case |
| 284 // the folder window can't fit on either side of the screen; we |
| 285 // don't want to loop forever. |
| 286 CGFloat x; |
| 287 int tries = 0; |
| 288 while (tries < 2) { |
| 289 // Try to grow right. |
| 290 if ([self subFolderGrowthToRight]) { |
| 291 tries++; |
| 292 x = NSMaxX([[parentButton_ window] frame]) - |
| 293 bookmarks::kBookmarkMenuOverlap; |
| 294 // If off the screen, switch direction. |
| 295 if ((x + windowWidth + bookmarks::kBookmarkHorizontalScreenPadding) > |
| 296 NSMaxX([[[self window] screen] frame])) { |
| 297 [self setSubFolderGrowthToRight:NO]; |
| 298 } else { |
| 299 return x; |
| 300 } |
| 301 } |
| 302 // Try to grow left. |
| 303 if (![self subFolderGrowthToRight]) { |
| 304 tries++; |
| 305 x = NSMinX([[parentButton_ window] frame]) + |
| 306 bookmarks::kBookmarkMenuOverlap - |
| 307 windowWidth; |
| 308 // If off the screen, switch direction. |
| 309 if (x < NSMinX([[[self window] screen] frame])) { |
| 310 [self setSubFolderGrowthToRight:YES]; |
| 311 } else { |
| 312 return x; |
| 313 } |
| 314 } |
| 315 } |
| 316 // Unhappy; do the best we can. |
| 317 return NSMaxX([[[self window] screen] frame]) - windowWidth; |
| 318 } |
| 319 |
| 320 |
| 266 // Compute and return the top left point of our window (screen | 321 // Compute and return the top left point of our window (screen |
| 267 // coordinates). The top left is positioned in a manner similar to | 322 // coordinates). The top left is positioned in a manner similar to |
| 268 // cascading menus. | 323 // cascading menus. Windows may grow to either the right or left of |
| 269 - (NSPoint)windowTopLeft { | 324 // their parent (if a sub-folder) so we need to know |windowWidth|. |
| 325 - (NSPoint)windowTopLeftForWidth:(int)windowWidth { |
| 270 NSPoint newWindowTopLeft; | 326 NSPoint newWindowTopLeft; |
| 271 if (![parentController_ isKindOfClass:[self class]]) { | 327 if (![parentController_ isKindOfClass:[self class]]) { |
| 272 // If we're not popping up from one of ourselves, we must be | 328 // If we're not popping up from one of ourselves, we must be |
| 273 // popping up from the bookmark bar itself. In this case, start | 329 // popping up from the bookmark bar itself. In this case, start |
| 274 // BELOW the parent button. Our left is the button left; our top | 330 // BELOW the parent button. Our left is the button left; our top |
| 275 // is bottom of button's parent view. | 331 // is bottom of button's parent view. |
| 276 NSPoint buttonBottomLeftInScreen = | 332 NSPoint buttonBottomLeftInScreen = |
| 277 [[parentButton_ window] | 333 [[parentButton_ window] |
| 278 convertBaseToScreen:[parentButton_ | 334 convertBaseToScreen:[parentButton_ |
| 279 convertPoint:NSZeroPoint toView:nil]]; | 335 convertPoint:NSZeroPoint toView:nil]]; |
| 280 NSPoint bookmarkBarBottomLeftInScreen = | 336 NSPoint bookmarkBarBottomLeftInScreen = |
| 281 [[parentButton_ window] | 337 [[parentButton_ window] |
| 282 convertBaseToScreen:[[parentButton_ superview] | 338 convertBaseToScreen:[[parentButton_ superview] |
| 283 convertPoint:NSZeroPoint toView:nil]]; | 339 convertPoint:NSZeroPoint toView:nil]]; |
| 284 newWindowTopLeft = NSMakePoint(buttonBottomLeftInScreen.x, | 340 newWindowTopLeft = NSMakePoint(buttonBottomLeftInScreen.x, |
| 285 bookmarkBarBottomLeftInScreen.y); | 341 bookmarkBarBottomLeftInScreen.y); |
| 286 } else { | 342 } else { |
| 287 // Our parent controller is another BookmarkBarFolderController. | 343 // Parent is a folder; grow right/left. |
| 288 // In this case, start with a slight overlap on the RIGHT of the | 344 newWindowTopLeft.x = [self childFolderWindowLeftForWidth:windowWidth]; |
| 289 // parent button, which looks much more menu-like than with none. | |
| 290 // Start to RIGHT of the button. | |
| 291 // TODO(jrg): If too far to right, pop left again. | |
| 292 // http://crbug.com/36225 | |
| 293 newWindowTopLeft.x = NSMaxX([[parentButton_ window] frame]) - | |
| 294 bookmarks::kBookmarkMenuOverlap; | |
| 295 NSPoint top = NSMakePoint(0, (NSMaxY([parentButton_ frame]) + | 345 NSPoint top = NSMakePoint(0, (NSMaxY([parentButton_ frame]) + |
| 296 bookmarks::kBookmarkVerticalPadding)); | 346 bookmarks::kBookmarkVerticalPadding)); |
| 297 NSPoint topOfWindow = | 347 NSPoint topOfWindow = |
| 298 [[parentButton_ window] | 348 [[parentButton_ window] |
| 299 convertBaseToScreen:[[parentButton_ superview] | 349 convertBaseToScreen:[[parentButton_ superview] |
| 300 convertPoint:top toView:nil]]; | 350 convertPoint:top toView:nil]]; |
| 301 newWindowTopLeft.y = topOfWindow.y; | 351 newWindowTopLeft.y = topOfWindow.y; |
| 302 } | 352 } |
| 303 return newWindowTopLeft; | 353 return newWindowTopLeft; |
| 304 } | 354 } |
| 305 | 355 |
| 306 // Set our window level to the right spot so we're above the menubar, dock, etc. | 356 // Set our window level to the right spot so we're above the menubar, dock, etc. |
| 307 // Factored out so we can override/noop in a unit test. | 357 // Factored out so we can override/noop in a unit test. |
| 308 - (void)configureWindowLevel { | 358 - (void)configureWindowLevel { |
| 309 [[self window] setLevel:NSPopUpMenuWindowLevel]; | 359 [[self window] setLevel:NSPopUpMenuWindowLevel]; |
| 310 } | 360 } |
| 311 | 361 |
| 312 - (void)adjustWindowForHeight:(int)windowHeight { | 362 - (void)adjustWindowForHeight:(int)windowHeight { |
| 313 // Adjust all button widths to be consistent, determine the best size for | 363 // Adjust all button widths to be consistent, determine the best size for |
| 314 // the window, and set the window frame. | 364 // the window, and set the window frame. |
| 315 CGFloat windowWidth = | 365 CGFloat windowWidth = |
| 316 [self adjustButtonWidths] + (2 * bookmarks::kBookmarkVerticalPadding) + | 366 [self adjustButtonWidths] + (2 * bookmarks::kBookmarkVerticalPadding) + |
| 317 bookmarks::kScrollViewContentWidthMargin; | 367 bookmarks::kScrollViewContentWidthMargin; |
| 318 NSPoint newWindowTopLeft = [self windowTopLeft]; | 368 NSPoint newWindowTopLeft = [self windowTopLeftForWidth:windowWidth]; |
| 319 NSRect windowFrame = NSMakeRect(newWindowTopLeft.x, | 369 NSRect windowFrame = NSMakeRect(newWindowTopLeft.x, |
| 320 newWindowTopLeft.y - windowHeight, | 370 newWindowTopLeft.y - windowHeight, |
| 321 windowWidth, | 371 windowWidth, |
| 322 windowHeight); | 372 windowHeight); |
| 323 | 373 |
| 324 // Make the window fit on screen, with a distance of at least |padding| from | |
| 325 // the sides. | |
| 326 DCHECK([[self window] screen]); | |
| 327 NSRect screenFrame = [[[self window] screen] frame]; | |
| 328 if (NSMaxX(windowFrame) + bookmarks::kBookmarkHorizontalScreenPadding > | |
| 329 NSMaxX(screenFrame)) | |
| 330 windowFrame.origin.x -= NSMaxX(windowFrame) + | |
| 331 bookmarks::kBookmarkHorizontalScreenPadding - NSMaxX(screenFrame); | |
| 332 // No 'else' to provide preference for the left side of the menu | |
| 333 // being visible if neither one fits. Wish I had an "bool isL2R()" | |
| 334 // function right here. | |
| 335 if (NSMinX(windowFrame) - bookmarks::kBookmarkHorizontalScreenPadding < | |
| 336 NSMinX(screenFrame)) | |
| 337 windowFrame.origin.x += NSMinX(screenFrame) - NSMinX(windowFrame) + | |
| 338 bookmarks::kBookmarkHorizontalScreenPadding; | |
| 339 | |
| 340 // Make the scrolled content be the right size (full size). | 374 // Make the scrolled content be the right size (full size). |
| 341 NSRect mainViewFrame = NSMakeRect(0, 0, | 375 NSRect mainViewFrame = NSMakeRect(0, 0, |
| 342 NSWidth(windowFrame) - | 376 NSWidth(windowFrame) - |
| 343 bookmarks::kScrollViewContentWidthMargin, | 377 bookmarks::kScrollViewContentWidthMargin, |
| 344 NSHeight(windowFrame)); | 378 NSHeight(windowFrame)); |
| 345 [mainView_ setFrame:mainViewFrame]; | 379 [mainView_ setFrame:mainViewFrame]; |
| 346 | 380 |
| 347 // Make sure the window fits on the screen. If not, constrain. | 381 // Make sure the window fits on the screen. If not, constrain. |
| 348 // We'll scroll to allow the user to see all the content. | 382 // We'll scroll to allow the user to see all the content. |
| 383 NSRect screenFrame = [[[self window] screen] frame]; |
| 349 screenFrame = NSInsetRect(screenFrame, 0, kScrollWindowVerticalMargin); | 384 screenFrame = NSInsetRect(screenFrame, 0, kScrollWindowVerticalMargin); |
| 350 if (!NSContainsRect(screenFrame, windowFrame)) { | 385 if (!NSContainsRect(screenFrame, windowFrame)) { |
| 351 scrollable_ = YES; | 386 scrollable_ = YES; |
| 352 windowFrame = NSIntersectionRect(screenFrame, windowFrame); | 387 windowFrame = NSIntersectionRect(screenFrame, windowFrame); |
| 353 } else { | 388 } else { |
| 354 scrollable_ = NO; | 389 scrollable_ = NO; |
| 355 } | 390 } |
| 356 [[self window] setFrame:windowFrame display:YES]; | 391 [[self window] setFrame:windowFrame display:YES]; |
| 357 // If scrollable then offset the view and show the arrows. | 392 // If scrollable then offset the view and show the arrows. |
| 358 if (scrollable_) { | 393 if (scrollable_) { |
| (...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 961 #pragma mark BookmarkButtonControllerProtocol | 996 #pragma mark BookmarkButtonControllerProtocol |
| 962 | 997 |
| 963 // Recursively close all bookmark folders. | 998 // Recursively close all bookmark folders. |
| 964 - (void)closeAllBookmarkFolders { | 999 - (void)closeAllBookmarkFolders { |
| 965 // Closing the top level implicitly closes all children. | 1000 // Closing the top level implicitly closes all children. |
| 966 [barController_ closeAllBookmarkFolders]; | 1001 [barController_ closeAllBookmarkFolders]; |
| 967 } | 1002 } |
| 968 | 1003 |
| 969 // Close our bookmark folder (a sub-controller) if we have one. | 1004 // Close our bookmark folder (a sub-controller) if we have one. |
| 970 - (void)closeBookmarkFolder:(id)sender { | 1005 - (void)closeBookmarkFolder:(id)sender { |
| 971 // folderController_ may be nil but that's OK. | 1006 if (folderController_) { |
| 972 [[folderController_ window] close]; | 1007 [self setSubFolderGrowthToRight:YES]; |
| 973 folderController_ = nil; | 1008 [[folderController_ window] close]; |
| 1009 folderController_ = nil; |
| 1010 } |
| 974 } | 1011 } |
| 975 | 1012 |
| 976 - (BookmarkModel*)bookmarkModel { | 1013 - (BookmarkModel*)bookmarkModel { |
| 977 return [barController_ bookmarkModel]; | 1014 return [barController_ bookmarkModel]; |
| 978 } | 1015 } |
| 979 | 1016 |
| 980 // TODO(jrg): Refactor BookmarkBarFolder common code. http://crbug.com/35966 | 1017 // TODO(jrg): Refactor BookmarkBarFolder common code. http://crbug.com/35966 |
| 981 // Most of the work (e.g. drop indicator) is taken care of in the | 1018 // Most of the work (e.g. drop indicator) is taken care of in the |
| 982 // folder_view. Here we handle hover open issues for subfolders. | 1019 // folder_view. Here we handle hover open issues for subfolders. |
| 983 // Caution: there are subtle differences between this one and | 1020 // Caution: there are subtle differences between this one and |
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1325 return [folderController_ controllerForNode:node]; | 1362 return [folderController_ controllerForNode:node]; |
| 1326 } | 1363 } |
| 1327 | 1364 |
| 1328 #pragma mark TestingAPI Only | 1365 #pragma mark TestingAPI Only |
| 1329 | 1366 |
| 1330 - (void)setIgnoreAnimations:(BOOL)ignore { | 1367 - (void)setIgnoreAnimations:(BOOL)ignore { |
| 1331 ignoreAnimations_ = ignore; | 1368 ignoreAnimations_ = ignore; |
| 1332 } | 1369 } |
| 1333 | 1370 |
| 1334 @end // BookmarkBarFolderController | 1371 @end // BookmarkBarFolderController |
| OLD | NEW |