| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 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/ui/cocoa/bookmarks/bookmark_bar_controller.h" | 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" |
| 6 | 6 |
| 7 #include "base/mac/mac_util.h" | 7 #include "base/mac/mac_util.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/sys_string_conversions.h" | 9 #include "base/sys_string_conversions.h" |
| 10 #include "chrome/browser/bookmarks/bookmark_editor.h" | 10 #include "chrome/browser/bookmarks/bookmark_editor.h" |
| 11 #include "chrome/browser/bookmarks/bookmark_model.h" | 11 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 12 #include "chrome/browser/bookmarks/bookmark_utils.h" | 12 #include "chrome/browser/bookmarks/bookmark_utils.h" |
| 13 #include "chrome/browser/extensions/extension_service.h" | 13 #include "chrome/browser/extensions/extension_service.h" |
| 14 #include "chrome/browser/prefs/pref_service.h" | 14 #include "chrome/browser/prefs/pref_service.h" |
| 15 #include "chrome/browser/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
| 16 #import "chrome/browser/themes/theme_service.h" | 16 #import "chrome/browser/themes/theme_service.h" |
| 17 #import "chrome/browser/themes/theme_service_factory.h" | 17 #import "chrome/browser/themes/theme_service_factory.h" |
| 18 #include "chrome/browser/ui/browser.h" | 18 #include "chrome/browser/ui/browser.h" |
| 19 #include "chrome/browser/ui/browser_list.h" | 19 #include "chrome/browser/ui/browser_list.h" |
| 20 #import "chrome/browser/ui/cocoa/background_gradient_view.h" | 20 #import "chrome/browser/ui/cocoa/background_gradient_view.h" |
| 21 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h" | 21 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h" |
| 22 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" | 22 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" |
| 23 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h" | |
| 24 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h" | 23 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h" |
| 25 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h" | 24 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h" |
| 26 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" | 25 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" |
| 27 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h" | 26 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h" |
| 28 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h" | 27 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h" |
| 29 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" | 28 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" |
| 30 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h" | 29 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h" |
| 31 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h" | 30 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h" |
| 32 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h" | 31 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h" |
| 33 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | 32 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 | 360 |
| 362 // When resized we may need to add new buttons, or remove them (if | 361 // When resized we may need to add new buttons, or remove them (if |
| 363 // no longer visible), or add/remove the "off the side" menu. | 362 // no longer visible), or add/remove the "off the side" menu. |
| 364 [[self view] setPostsFrameChangedNotifications:YES]; | 363 [[self view] setPostsFrameChangedNotifications:YES]; |
| 365 [[NSNotificationCenter defaultCenter] | 364 [[NSNotificationCenter defaultCenter] |
| 366 addObserver:self | 365 addObserver:self |
| 367 selector:@selector(frameDidChange) | 366 selector:@selector(frameDidChange) |
| 368 name:NSViewFrameDidChangeNotification | 367 name:NSViewFrameDidChangeNotification |
| 369 object:[self view]]; | 368 object:[self view]]; |
| 370 | 369 |
| 371 // Watch for things going to or from fullscreen. | |
| 372 [[NSNotificationCenter defaultCenter] | |
| 373 addObserver:self | |
| 374 selector:@selector(willEnterOrLeaveFullscreen:) | |
| 375 name:kWillEnterFullscreenNotification | |
| 376 object:nil]; | |
| 377 [[NSNotificationCenter defaultCenter] | |
| 378 addObserver:self | |
| 379 selector:@selector(willEnterOrLeaveFullscreen:) | |
| 380 name:kWillLeaveFullscreenNotification | |
| 381 object:nil]; | |
| 382 | |
| 383 // Don't pass ourself along (as 'self') until our init is completely | 370 // Don't pass ourself along (as 'self') until our init is completely |
| 384 // done. Thus, this call is (almost) last. | 371 // done. Thus, this call is (almost) last. |
| 385 bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_)); | 372 bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_)); |
| 386 } | 373 } |
| 387 | 374 |
| 388 // Called by our main view (a BookmarkBarView) when it gets moved to a | 375 // Called by our main view (a BookmarkBarView) when it gets moved to a |
| 389 // window. We perform operations which need to know the relevant | 376 // window. We perform operations which need to know the relevant |
| 390 // window (e.g. watch for a window close) so they can't be performed | 377 // window (e.g. watch for a window close) so they can't be performed |
| 391 // earlier (such as in awakeFromNib). | 378 // earlier (such as in awakeFromNib). |
| 392 - (void)viewDidMoveToWindow { | 379 - (void)viewDidMoveToWindow { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 403 [defaultCenter addObserver:self | 390 [defaultCenter addObserver:self |
| 404 selector:@selector(parentWindowWillClose:) | 391 selector:@selector(parentWindowWillClose:) |
| 405 name:NSWindowWillCloseNotification | 392 name:NSWindowWillCloseNotification |
| 406 object:[[self view] window]]; | 393 object:[[self view] window]]; |
| 407 [defaultCenter addObserver:self | 394 [defaultCenter addObserver:self |
| 408 selector:@selector(parentWindowDidResignMain:) | 395 selector:@selector(parentWindowDidResignMain:) |
| 409 name:NSWindowDidResignMainNotification | 396 name:NSWindowDidResignMainNotification |
| 410 object:[[self view] window]]; | 397 object:[[self view] window]]; |
| 411 } | 398 } |
| 412 | 399 |
| 413 // When going fullscreen we can run into trouble. Our view is removed | |
| 414 // from the non-fullscreen window before the non-fullscreen window | |
| 415 // loses key, so our parentDidResignKey: callback never gets called. | |
| 416 // In addition, a bookmark folder controller needs to be autoreleased | |
| 417 // (in case it's in the event chain when closed), but the release | |
| 418 // implicitly needs to happen while it's connected to the original | |
| 419 // (non-fullscreen) window to "unlock bar visibility". Such a | |
| 420 // contract isn't honored when going fullscreen with the menu option | |
| 421 // (not with the keyboard shortcut). We fake it as best we can here. | |
| 422 // We have a similar problem leaving fullscreen. | |
| 423 - (void)willEnterOrLeaveFullscreen:(NSNotification*)notification { | |
| 424 if (folderController_) { | |
| 425 [self childFolderWillClose:folderController_]; | |
| 426 [self closeFolderAndStopTrackingMenus]; | |
| 427 } | |
| 428 } | |
| 429 | |
| 430 // NSNotificationCenter callback. | 400 // NSNotificationCenter callback. |
| 431 - (void)parentWindowWillClose:(NSNotification*)notification { | 401 - (void)parentWindowWillClose:(NSNotification*)notification { |
| 432 [self closeFolderAndStopTrackingMenus]; | 402 [self closeFolderAndStopTrackingMenus]; |
| 433 } | 403 } |
| 434 | 404 |
| 435 // NSNotificationCenter callback. | 405 // NSNotificationCenter callback. |
| 436 - (void)parentWindowDidResignMain:(NSNotification*)notification { | 406 - (void)parentWindowDidResignMain:(NSNotification*)notification { |
| 437 [self closeFolderAndStopTrackingMenus]; | 407 [self closeFolderAndStopTrackingMenus]; |
| 438 } | 408 } |
| 439 | 409 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 if (node == nil || | 510 if (node == nil || |
| 541 node == bookmarkModel_->bookmark_bar_node() || | 511 node == bookmarkModel_->bookmark_bar_node() || |
| 542 node == bookmarkModel_->other_node() || | 512 node == bookmarkModel_->other_node() || |
| 543 node == bookmarkModel_->synced_node()) | 513 node == bookmarkModel_->synced_node()) |
| 544 return NO; | 514 return NO; |
| 545 return YES; | 515 return YES; |
| 546 } | 516 } |
| 547 | 517 |
| 548 #pragma mark Actions | 518 #pragma mark Actions |
| 549 | 519 |
| 550 // Helper methods called on the main thread by runMenuFlashThread. | |
| 551 | |
| 552 - (void)setButtonFlashStateOn:(id)sender { | |
| 553 [sender highlight:YES]; | |
| 554 } | |
| 555 | |
| 556 - (void)setButtonFlashStateOff:(id)sender { | |
| 557 [sender highlight:NO]; | |
| 558 } | |
| 559 | |
| 560 -(void)cleanupAfterMenuFlashThread:(id)sender { | |
| 561 [self closeFolderAndStopTrackingMenus]; | |
| 562 | |
| 563 // Items retained by doMenuFlashOnSeparateThread below. | |
| 564 [sender release]; | |
| 565 [self release]; | |
| 566 } | |
| 567 | |
| 568 // End runMenuFlashThread helper methods. | |
| 569 | |
| 570 // This call is invoked only by doMenuFlashOnSeparateThread below. | |
| 571 // It makes the selected BookmarkButton (which is masquerading as a menu item) | |
| 572 // flash a few times to give confirmation feedback, then it closes the menu. | |
| 573 // It spends all its time sleeping or scheduling UI work on the main thread. | |
| 574 - (void)runMenuFlashThread:(id)sender { | |
| 575 | |
| 576 // Check this is not running on the main thread, as it sleeps. | |
| 577 DCHECK(![NSThread isMainThread]); | |
| 578 | |
| 579 // Duration of flash phases and number of flashes designed to evoke a | |
| 580 // slightly retro "more mac-like than the Mac" feel. | |
| 581 // Current Cocoa UI has a barely perceptible flash,probably because Apple | |
| 582 // doesn't fire the action til after the animation and so there's a hurry. | |
| 583 // As this code is fully asynchronous, it can take its time. | |
| 584 const float kBBOnFlashTime = 0.08; | |
| 585 const float kBBOffFlashTime = 0.08; | |
| 586 const int kBookmarkButtonMenuFlashes = 3; | |
| 587 | |
| 588 for (int count = 0 ; count < kBookmarkButtonMenuFlashes ; count++) { | |
| 589 [self performSelectorOnMainThread:@selector(setButtonFlashStateOn:) | |
| 590 withObject:sender | |
| 591 waitUntilDone:NO]; | |
| 592 [NSThread sleepForTimeInterval:kBBOnFlashTime]; | |
| 593 [self performSelectorOnMainThread:@selector(setButtonFlashStateOff:) | |
| 594 withObject:sender | |
| 595 waitUntilDone:NO]; | |
| 596 [NSThread sleepForTimeInterval:kBBOffFlashTime]; | |
| 597 } | |
| 598 [self performSelectorOnMainThread:@selector(cleanupAfterMenuFlashThread:) | |
| 599 withObject:sender | |
| 600 waitUntilDone:NO]; | |
| 601 } | |
| 602 | |
| 603 // Non-blocking call which starts the process to make the selected menu item | |
| 604 // flash a few times to give confirmation feedback, after which it closes the | |
| 605 // menu. The item is of course actually a BookmarkButton masquerading as a menu | |
| 606 // item). | |
| 607 - (void)doMenuFlashOnSeparateThread:(id)sender { | |
| 608 | |
| 609 // Ensure that self and sender don't go away before the animation completes. | |
| 610 // These retains are balanced in cleanupAfterMenuFlashThread above. | |
| 611 [self retain]; | |
| 612 [sender retain]; | |
| 613 [NSThread detachNewThreadSelector:@selector(runMenuFlashThread:) | |
| 614 toTarget:self | |
| 615 withObject:sender]; | |
| 616 } | |
| 617 | |
| 618 - (IBAction)openBookmark:(id)sender { | 520 - (IBAction)openBookmark:(id)sender { |
| 619 BOOL isMenuItem = [[sender cell] isFolderButtonCell]; | 521 BOOL isMenuItem = [[sender cell] isFolderButtonCell]; |
| 620 BOOL animate = isMenuItem && [self animationEnabled]; | 522 BOOL animate = isMenuItem && [self animationEnabled]; |
| 621 if (animate) | |
| 622 [self doMenuFlashOnSeparateThread:sender]; | |
| 623 DCHECK([sender respondsToSelector:@selector(bookmarkNode)]); | 523 DCHECK([sender respondsToSelector:@selector(bookmarkNode)]); |
| 624 const BookmarkNode* node = [sender bookmarkNode]; | 524 const BookmarkNode* node = [sender bookmarkNode]; |
| 625 WindowOpenDisposition disposition = | 525 WindowOpenDisposition disposition = |
| 626 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); | 526 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); |
| 627 RecordAppLaunch(browser_->profile(), node->url()); | 527 RecordAppLaunch(browser_->profile(), node->url()); |
| 628 [self openURL:node->url() disposition:disposition]; | 528 [self openURL:node->url() disposition:disposition]; |
| 629 | 529 |
| 630 if (!animate) | 530 if (!animate) |
| 631 [self closeFolderAndStopTrackingMenus]; | 531 [self closeFolderAndStopTrackingMenus]; |
| 632 } | 532 } |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 854 bookmarks::kBookmarkHorizontalPadding)); | 754 bookmarks::kBookmarkHorizontalPadding)); |
| 855 } else { | 755 } else { |
| 856 frame.origin.x = (NSMaxX([otherBookmarksButton_ frame]) - frame.size.width); | 756 frame.origin.x = (NSMaxX([otherBookmarksButton_ frame]) - frame.size.width); |
| 857 } | 757 } |
| 858 [offTheSideButton_ setFrame:frame]; | 758 [offTheSideButton_ setFrame:frame]; |
| 859 } | 759 } |
| 860 | 760 |
| 861 // Configure the off-the-side button (e.g. specify the node range, | 761 // Configure the off-the-side button (e.g. specify the node range, |
| 862 // check if we should enable or disable it, etc). | 762 // check if we should enable or disable it, etc). |
| 863 - (void)configureOffTheSideButtonContentsAndVisibility { | 763 - (void)configureOffTheSideButtonContentsAndVisibility { |
| 864 // If deleting a button while off-the-side is open, buttons may be | |
| 865 // promoted from off-the-side to the bar. Accomodate. | |
| 866 if (folderController_ && | |
| 867 ([folderController_ parentButton] == offTheSideButton_)) { | |
| 868 [folderController_ reconfigureMenu]; | |
| 869 } | |
| 870 | |
| 871 [[offTheSideButton_ cell] setStartingChildIndex:displayedButtonCount_]; | 764 [[offTheSideButton_ cell] setStartingChildIndex:displayedButtonCount_]; |
| 872 [[offTheSideButton_ cell] | 765 [[offTheSideButton_ cell] |
| 873 setBookmarkNode:bookmarkModel_->bookmark_bar_node()]; | 766 setBookmarkNode:bookmarkModel_->bookmark_bar_node()]; |
| 874 int bookmarkChildren = bookmarkModel_->bookmark_bar_node()->child_count(); | 767 int bookmarkChildren = bookmarkModel_->bookmark_bar_node()->child_count(); |
| 875 if (bookmarkChildren > displayedButtonCount_) { | 768 if (bookmarkChildren > displayedButtonCount_) { |
| 876 [offTheSideButton_ setHidden:NO]; | 769 [offTheSideButton_ setHidden:NO]; |
| 877 } else { | 770 } else { |
| 878 // If we just deleted the last item in an off-the-side menu so the | 771 // If we just deleted the last item in an off-the-side menu so the |
| 879 // button will be going away, make sure the menu goes away. | 772 // button will be going away, make sure the menu goes away. |
| 880 if (folderController_ && | 773 if (folderController_ && |
| (...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1814 // All other clicks on the bookmarks bar are counted as 'outside' | 1707 // All other clicks on the bookmarks bar are counted as 'outside' |
| 1815 // because they should close any open bookmark folder menu. | 1708 // because they should close any open bookmark folder menu. |
| 1816 if (eventWindow == myWindow) { | 1709 if (eventWindow == myWindow) { |
| 1817 NSView* hitView = | 1710 NSView* hitView = |
| 1818 [[eventWindow contentView] hitTest:[event locationInWindow]]; | 1711 [[eventWindow contentView] hitTest:[event locationInWindow]]; |
| 1819 if (hitView == [folderController_ parentButton]) | 1712 if (hitView == [folderController_ parentButton]) |
| 1820 return NO; | 1713 return NO; |
| 1821 if (![hitView isDescendantOf:[self view]] || hitView == buttonView_) | 1714 if (![hitView isDescendantOf:[self view]] || hitView == buttonView_) |
| 1822 return YES; | 1715 return YES; |
| 1823 } | 1716 } |
| 1824 // If a click in a bookmark bar folder window and that isn't | |
| 1825 // one of my bookmark bar folders, YES is click outside. | |
| 1826 if (![eventWindow isKindOfClass:[BookmarkBarFolderWindow | |
| 1827 class]]) { | |
| 1828 return YES; | |
| 1829 } | |
| 1830 break; | 1717 break; |
| 1831 case NSKeyDown: { | 1718 case NSKeyDown: { |
| 1832 // Event hooks often see the same keydown event twice due to the way key | 1719 // Event hooks often see the same keydown event twice due to the way key |
| 1833 // events get dispatched and redispatched, so ignore if this keydown | 1720 // events get dispatched and redispatched, so ignore if this keydown |
| 1834 // event has the EXACT same timestamp as the previous keydown. | 1721 // event has the EXACT same timestamp as the previous keydown. |
| 1835 static NSTimeInterval lastKeyDownEventTime; | 1722 static NSTimeInterval lastKeyDownEventTime; |
| 1836 NSTimeInterval thisTime = [event timestamp]; | 1723 NSTimeInterval thisTime = [event timestamp]; |
| 1837 if (lastKeyDownEventTime != thisTime) { | 1724 if (lastKeyDownEventTime != thisTime) { |
| 1838 lastKeyDownEventTime = thisTime; | 1725 lastKeyDownEventTime = thisTime; |
| 1839 if ([event modifierFlags] & NSCommandKeyMask) | 1726 if ([event modifierFlags] & NSCommandKeyMask) |
| 1840 return YES; | 1727 return YES; |
| 1841 else if (folderController_) | |
| 1842 return [folderController_ handleInputText:[event characters]]; | |
| 1843 } | 1728 } |
| 1844 return NO; | 1729 return NO; |
| 1845 } | 1730 } |
| 1846 case NSKeyUp: | 1731 case NSKeyUp: |
| 1847 return NO; | 1732 return NO; |
| 1848 case NSLeftMouseDragged: | 1733 case NSLeftMouseDragged: |
| 1849 // We can get here with the following sequence: | 1734 // We can get here with the following sequence: |
| 1850 // - open a bookmark folder | 1735 // - open a bookmark folder |
| 1851 // - right-click (and unclick) on it to open context menu | 1736 // - right-click (and unclick) on it to open context menu |
| 1852 // - move mouse to window titlebar then click-drag it by the titlebar | 1737 // - move mouse to window titlebar then click-drag it by the titlebar |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2189 if (cellnode == node) { | 2074 if (cellnode == node) { |
| 2190 [[button cell] setBookmarkCellText:[button title] | 2075 [[button cell] setBookmarkCellText:[button title] |
| 2191 image:[self faviconForNode:node]]; | 2076 image:[self faviconForNode:node]]; |
| 2192 // Adding an image means we might need more room for the | 2077 // Adding an image means we might need more room for the |
| 2193 // bookmark. Test for it by growing the button (if needed) | 2078 // bookmark. Test for it by growing the button (if needed) |
| 2194 // and shifting everything else over. | 2079 // and shifting everything else over. |
| 2195 [self checkForBookmarkButtonGrowth:button]; | 2080 [self checkForBookmarkButtonGrowth:button]; |
| 2196 return; | 2081 return; |
| 2197 } | 2082 } |
| 2198 } | 2083 } |
| 2199 | |
| 2200 if (folderController_) | |
| 2201 [folderController_ faviconLoadedForNode:node]; | |
| 2202 } | 2084 } |
| 2203 | 2085 |
| 2204 // TODO(jrg): for now this is brute force. | 2086 // TODO(jrg): for now this is brute force. |
| 2205 - (void)nodeChildrenReordered:(BookmarkModel*)model | 2087 - (void)nodeChildrenReordered:(BookmarkModel*)model |
| 2206 node:(const BookmarkNode*)node { | 2088 node:(const BookmarkNode*)node { |
| 2207 [self loaded:model]; | 2089 [self loaded:model]; |
| 2208 } | 2090 } |
| 2209 | 2091 |
| 2210 #pragma mark BookmarkBarState Protocol | 2092 #pragma mark BookmarkBarState Protocol |
| 2211 | 2093 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2300 // a subfolder menu. | 2182 // a subfolder menu. |
| 2301 if (!showFolderMenus_) | 2183 if (!showFolderMenus_) |
| 2302 return; | 2184 return; |
| 2303 | 2185 |
| 2304 // From here down: same logic as BookmarkBarFolderController. | 2186 // From here down: same logic as BookmarkBarFolderController. |
| 2305 // TODO(jrg): find a way to share these 4 non-comment lines? | 2187 // TODO(jrg): find a way to share these 4 non-comment lines? |
| 2306 // http://crbug.com/35966 | 2188 // http://crbug.com/35966 |
| 2307 // If already opened, then we exited but re-entered the button, so do nothing. | 2189 // If already opened, then we exited but re-entered the button, so do nothing. |
| 2308 if ([folderController_ parentButton] == sender) | 2190 if ([folderController_ parentButton] == sender) |
| 2309 return; | 2191 return; |
| 2310 // Else open a new one if it makes sense to do so. | |
| 2311 if ([sender bookmarkNode]->is_folder()) { | |
| 2312 // Update |hoverButton_| so that it corresponds to the open folder. | |
| 2313 hoverButton_.reset([sender retain]); | |
| 2314 [folderTarget_ openBookmarkFolderFromButton:sender]; | |
| 2315 } else { | |
| 2316 // We're over a non-folder bookmark so close any old folders. | |
| 2317 [folderController_ close]; | |
| 2318 folderController_ = nil; | |
| 2319 } | |
| 2320 } | 2192 } |
| 2321 | 2193 |
| 2322 // BookmarkButtonDelegate protocol implementation. | 2194 // BookmarkButtonDelegate protocol implementation. |
| 2323 - (void)mouseExitedButton:(id)sender event:(NSEvent*)event { | 2195 - (void)mouseExitedButton:(id)sender event:(NSEvent*)event { |
| 2324 // Don't care; do nothing. | 2196 // Don't care; do nothing. |
| 2325 // This is different behavior that the folder menus. | 2197 // This is different behavior that the folder menus. |
| 2326 } | 2198 } |
| 2327 | 2199 |
| 2328 - (NSWindow*)browserWindow { | 2200 - (NSWindow*)browserWindow { |
| 2329 return [[self view] window]; | 2201 return [[self view] window]; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2351 [self resetAllButtonPositionsWithAnimation:YES]; | 2223 [self resetAllButtonPositionsWithAnimation:YES]; |
| 2352 } | 2224 } |
| 2353 | 2225 |
| 2354 | 2226 |
| 2355 #pragma mark BookmarkButtonControllerProtocol | 2227 #pragma mark BookmarkButtonControllerProtocol |
| 2356 | 2228 |
| 2357 // Close all bookmark folders. "Folder" here is the fake menu for | 2229 // Close all bookmark folders. "Folder" here is the fake menu for |
| 2358 // bookmark folders, not a button context menu. | 2230 // bookmark folders, not a button context menu. |
| 2359 - (void)closeAllBookmarkFolders { | 2231 - (void)closeAllBookmarkFolders { |
| 2360 [self watchForExitEvent:NO]; | 2232 [self watchForExitEvent:NO]; |
| 2361 [folderController_ close]; | 2233 [folderController_ closeMenu]; |
| 2362 folderController_ = nil; | 2234 folderController_ = nil; |
| 2363 } | 2235 } |
| 2364 | 2236 |
| 2365 - (void)closeBookmarkFolder:(id)sender { | 2237 - (void)closeBookmarkFolder:(id)sender { |
| 2366 // We're the top level, so close one means close them all. | 2238 // We're the top level, so close one means close them all. |
| 2367 [self closeAllBookmarkFolders]; | 2239 [self closeAllBookmarkFolders]; |
| 2368 } | 2240 } |
| 2369 | 2241 |
| 2370 - (BookmarkModel*)bookmarkModel { | 2242 - (BookmarkModel*)bookmarkModel { |
| 2371 return bookmarkModel_; | 2243 return bookmarkModel_; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2406 target]]; | 2278 target]]; |
| 2407 // Unlike BookmarkBarFolderController, we do not delay the close | 2279 // Unlike BookmarkBarFolderController, we do not delay the close |
| 2408 // of the previous one. Given the lack of diagonal movement, | 2280 // of the previous one. Given the lack of diagonal movement, |
| 2409 // there is no need, and it feels awkward to do so. See | 2281 // there is no need, and it feels awkward to do so. See |
| 2410 // comments about kDragHoverCloseDelay in | 2282 // comments about kDragHoverCloseDelay in |
| 2411 // bookmark_bar_folder_controller.mm for more details. | 2283 // bookmark_bar_folder_controller.mm for more details. |
| 2412 [[hoverButton_ target] closeBookmarkFolder:hoverButton_]; | 2284 [[hoverButton_ target] closeBookmarkFolder:hoverButton_]; |
| 2413 hoverButton_.reset(); | 2285 hoverButton_.reset(); |
| 2414 } | 2286 } |
| 2415 hoverButton_.reset([button retain]); | 2287 hoverButton_.reset([button retain]); |
| 2416 DCHECK([[hoverButton_ target] | |
| 2417 respondsToSelector:@selector(openBookmarkFolderFromButton:)]); | |
| 2418 [[hoverButton_ target] | |
| 2419 performSelector:@selector(openBookmarkFolderFromButton:) | |
| 2420 withObject:hoverButton_ | |
| 2421 afterDelay:bookmarks::kDragHoverOpenDelay | |
| 2422 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; | |
| 2423 } | 2288 } |
| 2424 if (!button) { | 2289 if (!button) { |
| 2425 if (hoverButton_) { | 2290 if (hoverButton_) { |
| 2426 [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_ target]]; | |
| 2427 [[hoverButton_ target] closeBookmarkFolder:hoverButton_]; | 2291 [[hoverButton_ target] closeBookmarkFolder:hoverButton_]; |
| 2428 hoverButton_.reset(); | 2292 hoverButton_.reset(); |
| 2429 } | 2293 } |
| 2430 } | 2294 } |
| 2431 | 2295 |
| 2432 // Thrown away but kept to be consistent with the draggingEntered: interface. | 2296 // Thrown away but kept to be consistent with the draggingEntered: interface. |
| 2433 return NSDragOperationMove; | 2297 return NSDragOperationMove; |
| 2434 } | 2298 } |
| 2435 | 2299 |
| 2436 - (void)draggingExited:(id<NSDraggingInfo>)info { | 2300 - (void)draggingExited:(id<NSDraggingInfo>)info { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2521 } else { | 2385 } else { |
| 2522 x = 0.5 * bookmarks::kBookmarkHorizontalPadding; | 2386 x = 0.5 * bookmarks::kBookmarkHorizontalPadding; |
| 2523 } | 2387 } |
| 2524 } else { | 2388 } else { |
| 2525 NOTREACHED(); | 2389 NOTREACHED(); |
| 2526 } | 2390 } |
| 2527 | 2391 |
| 2528 return x; | 2392 return x; |
| 2529 } | 2393 } |
| 2530 | 2394 |
| 2531 - (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child { | |
| 2532 // If the bookmarkbar is not in detached mode, lock bar visibility, forcing | |
| 2533 // the overlay to stay open when in fullscreen mode. | |
| 2534 if (![self isInState:bookmarks::kDetachedState] && | |
| 2535 ![self isAnimatingToState:bookmarks::kDetachedState]) { | |
| 2536 BrowserWindowController* browserController = | |
| 2537 [BrowserWindowController browserWindowControllerForView:[self view]]; | |
| 2538 [browserController lockBarVisibilityForOwner:child | |
| 2539 withAnimation:NO | |
| 2540 delay:NO]; | |
| 2541 } | |
| 2542 } | |
| 2543 | |
| 2544 - (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child { | |
| 2545 // Release bar visibility, allowing the overlay to close if in fullscreen | |
| 2546 // mode. | |
| 2547 BrowserWindowController* browserController = | |
| 2548 [BrowserWindowController browserWindowControllerForView:[self view]]; | |
| 2549 [browserController releaseBarVisibilityForOwner:child | |
| 2550 withAnimation:NO | |
| 2551 delay:NO]; | |
| 2552 } | |
| 2553 | |
| 2554 // Add a new folder controller as triggered by the given folder button. | 2395 // Add a new folder controller as triggered by the given folder button. |
| 2555 - (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton { | 2396 - (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton { |
| 2556 | 2397 |
| 2557 // If doing a close/open, make sure the fullscreen chrome doesn't | 2398 // If doing a close/open, make sure the fullscreen chrome doesn't |
| 2558 // have a chance to begin animating away in the middle of things. | 2399 // have a chance to begin animating away in the middle of things. |
| 2559 BrowserWindowController* browserController = | 2400 BrowserWindowController* browserController = |
| 2560 [BrowserWindowController browserWindowControllerForView:[self view]]; | 2401 [BrowserWindowController browserWindowControllerForView:[self view]]; |
| 2561 // Confirm we're not re-locking with ourself as an owner before locking. | 2402 // Confirm we're not re-locking with ourself as an owner before locking. |
| 2562 DCHECK([browserController isBarVisibilityLockedForOwner:self] == NO); | 2403 DCHECK([browserController isBarVisibilityLockedForOwner:self] == NO); |
| 2563 [browserController lockBarVisibilityForOwner:self | 2404 [browserController lockBarVisibilityForOwner:self |
| 2564 withAnimation:NO | 2405 withAnimation:NO |
| 2565 delay:NO]; | 2406 delay:NO]; |
| 2566 | 2407 |
| 2567 if (folderController_) | 2408 if (folderController_) |
| 2568 [self closeAllBookmarkFolders]; | 2409 [self closeAllBookmarkFolders]; |
| 2569 | 2410 |
| 2570 // Folder controller, like many window controllers, owns itself. | 2411 // Folder controller, like many window controllers, owns itself. |
| 2571 folderController_ = | 2412 folderController_ = |
| 2572 [[BookmarkBarFolderController alloc] initWithParentButton:parentButton | 2413 [[BookmarkBarFolderController alloc] initWithParentButton:parentButton |
| 2573 parentController:nil | 2414 bookmarkModel:bookmarkModel_ |
| 2574 barController:self]; | 2415 barController:self]; |
| 2575 [folderController_ showWindow:self]; | 2416 [folderController_ autorelease]; |
| 2417 [folderController_ openMenu]; |
| 2576 | 2418 |
| 2577 // Only BookmarkBarController has this; the | 2419 // Only BookmarkBarController has this; the |
| 2578 // BookmarkBarFolderController does not. | 2420 // BookmarkBarFolderController does not. |
| 2579 [self watchForExitEvent:YES]; | 2421 [self watchForExitEvent:YES]; |
| 2580 | 2422 |
| 2581 // No longer need to hold the lock; the folderController_ now owns it. | 2423 // No longer need to hold the lock; the folderController_ now owns it. |
| 2582 [browserController releaseBarVisibilityForOwner:self | 2424 [browserController releaseBarVisibilityForOwner:self |
| 2583 withAnimation:NO | 2425 withAnimation:NO |
| 2584 delay:NO]; | 2426 delay:NO]; |
| 2585 } | 2427 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2610 ++displayedButtonCount_; | 2452 ++displayedButtonCount_; |
| 2611 [buttons_ insertObject:newButton atIndex:buttonIndex]; | 2453 [buttons_ insertObject:newButton atIndex:buttonIndex]; |
| 2612 [buttonView_ addSubview:newButton]; | 2454 [buttonView_ addSubview:newButton]; |
| 2613 [self resetAllButtonPositionsWithAnimation:NO]; | 2455 [self resetAllButtonPositionsWithAnimation:NO]; |
| 2614 // See if any buttons need to be pushed off to or brought in from the side. | 2456 // See if any buttons need to be pushed off to or brought in from the side. |
| 2615 [self reconfigureBookmarkBar]; | 2457 [self reconfigureBookmarkBar]; |
| 2616 } else { | 2458 } else { |
| 2617 // A button from somewhere else (not the bar) is being moved to the | 2459 // A button from somewhere else (not the bar) is being moved to the |
| 2618 // off-the-side so insure it gets redrawn if its showing. | 2460 // off-the-side so insure it gets redrawn if its showing. |
| 2619 [self reconfigureBookmarkBar]; | 2461 [self reconfigureBookmarkBar]; |
| 2620 [folderController_ reconfigureMenu]; | |
| 2621 } | 2462 } |
| 2622 } | 2463 } |
| 2623 | 2464 |
| 2624 // TODO(mrossetti): Duplicate code with BookmarkBarFolderController. | 2465 // TODO(mrossetti): Duplicate code with BookmarkBarFolderController. |
| 2625 // http://crbug.com/35966 | 2466 // http://crbug.com/35966 |
| 2626 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { | 2467 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { |
| 2627 DCHECK([urls count] == [titles count]); | 2468 DCHECK([urls count] == [titles count]); |
| 2628 BOOL nodesWereAdded = NO; | 2469 BOOL nodesWereAdded = NO; |
| 2629 // Figure out where these new bookmarks nodes are to be added. | 2470 // Figure out where these new bookmarks nodes are to be added. |
| 2630 BookmarkButton* button = [self buttonForDroppingOnAtPoint:point]; | 2471 BookmarkButton* button = [self buttonForDroppingOnAtPoint:point]; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2678 [movedButton setHidden:NO]; | 2519 [movedButton setHidden:NO]; |
| 2679 [self resetAllButtonPositionsWithAnimation:NO]; | 2520 [self resetAllButtonPositionsWithAnimation:NO]; |
| 2680 } else if (fromIndex < buttonCount) { | 2521 } else if (fromIndex < buttonCount) { |
| 2681 // A button is being removed from the bar and added to off-the-side. | 2522 // A button is being removed from the bar and added to off-the-side. |
| 2682 // By now the node has already been inserted into the model so the | 2523 // By now the node has already been inserted into the model so the |
| 2683 // button to be added is represented by |toIndex|. Things get | 2524 // button to be added is represented by |toIndex|. Things get |
| 2684 // complicated because the off-the-side is showing and must be redrawn | 2525 // complicated because the off-the-side is showing and must be redrawn |
| 2685 // while possibly re-laying out the bookmark bar. | 2526 // while possibly re-laying out the bookmark bar. |
| 2686 [self removeButton:fromIndex animate:NO]; | 2527 [self removeButton:fromIndex animate:NO]; |
| 2687 [self reconfigureBookmarkBar]; | 2528 [self reconfigureBookmarkBar]; |
| 2688 [folderController_ reconfigureMenu]; | |
| 2689 } else if (toIndex < buttonCount) { | 2529 } else if (toIndex < buttonCount) { |
| 2690 // A button is being added to the bar and removed from off-the-side. | 2530 // A button is being added to the bar and removed from off-the-side. |
| 2691 // By now the node has already been inserted into the model so the | 2531 // By now the node has already been inserted into the model so the |
| 2692 // button to be added is represented by |toIndex|. | 2532 // button to be added is represented by |toIndex|. |
| 2693 const BookmarkNode* node = bookmarkModel_->bookmark_bar_node(); | 2533 const BookmarkNode* node = bookmarkModel_->bookmark_bar_node(); |
| 2694 const BookmarkNode* movedNode = node->GetChild(toIndex); | 2534 const BookmarkNode* movedNode = node->GetChild(toIndex); |
| 2695 DCHECK(movedNode); | 2535 DCHECK(movedNode); |
| 2696 [self addButtonForNode:movedNode atIndex:toIndex]; | 2536 [self addButtonForNode:movedNode atIndex:toIndex]; |
| 2697 [self reconfigureBookmarkBar]; | 2537 [self reconfigureBookmarkBar]; |
| 2698 } else { | |
| 2699 // A button is being moved within the off-the-side. | |
| 2700 fromIndex -= buttonCount; | |
| 2701 toIndex -= buttonCount; | |
| 2702 [folderController_ moveButtonFromIndex:fromIndex toIndex:toIndex]; | |
| 2703 } | 2538 } |
| 2704 } | 2539 } |
| 2705 } | 2540 } |
| 2706 | 2541 |
| 2707 - (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate { | 2542 - (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate { |
| 2708 if (buttonIndex < (NSInteger)[buttons_ count]) { | 2543 if (buttonIndex < (NSInteger)[buttons_ count]) { |
| 2709 // The button being removed is showing in the bar. | 2544 // The button being removed is showing in the bar. |
| 2710 BookmarkButton* oldButton = [buttons_ objectAtIndex:buttonIndex]; | 2545 BookmarkButton* oldButton = [buttons_ objectAtIndex:buttonIndex]; |
| 2711 if (oldButton == [folderController_ parentButton]) { | 2546 if (oldButton == [folderController_ parentButton]) { |
| 2712 // If we are deleting a button whose folder is currently open, close it! | 2547 // If we are deleting a button whose folder is currently open, close it! |
| 2713 [self closeAllBookmarkFolders]; | 2548 [self closeAllBookmarkFolders]; |
| 2714 } | 2549 } |
| 2715 if (animate && !ignoreAnimations_ && [self isVisible] && | 2550 if (animate && !ignoreAnimations_ && [self isVisible] && |
| 2716 [[self browserWindow] isMainWindow]) { | 2551 [[self browserWindow] isMainWindow]) { |
| 2717 NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation]; | 2552 NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation]; |
| 2718 NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint, | 2553 NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint, |
| 2719 NSZeroSize, nil, nil, nil); | 2554 NSZeroSize, nil, nil, nil); |
| 2720 } | 2555 } |
| 2721 [oldButton setDelegate:nil]; | 2556 [oldButton setDelegate:nil]; |
| 2722 [oldButton removeFromSuperview]; | 2557 [oldButton removeFromSuperview]; |
| 2723 [buttons_ removeObjectAtIndex:buttonIndex]; | 2558 [buttons_ removeObjectAtIndex:buttonIndex]; |
| 2724 --displayedButtonCount_; | 2559 --displayedButtonCount_; |
| 2725 [self resetAllButtonPositionsWithAnimation:YES]; | 2560 [self resetAllButtonPositionsWithAnimation:YES]; |
| 2726 [self reconfigureBookmarkBar]; | 2561 [self reconfigureBookmarkBar]; |
| 2727 } else if (folderController_ && | |
| 2728 [folderController_ parentButton] == offTheSideButton_) { | |
| 2729 // The button being removed is in the OTS (off-the-side) and the OTS | |
| 2730 // menu is showing so we need to remove the button. | |
| 2731 NSInteger index = buttonIndex - displayedButtonCount_; | |
| 2732 [folderController_ removeButton:index animate:YES]; | |
| 2733 } | 2562 } |
| 2734 } | 2563 } |
| 2735 | 2564 |
| 2736 - (id<BookmarkButtonControllerProtocol>)controllerForNode: | 2565 - (id<BookmarkButtonControllerProtocol>)controllerForNode: |
| 2737 (const BookmarkNode*)node { | 2566 (const BookmarkNode*)node { |
| 2738 // See if it's in the bar, then if it is in the hierarchy of visible | 2567 // See if it's in the bar, then if it is in the hierarchy of visible |
| 2739 // folder menus. | 2568 // folder menus. |
| 2740 if (bookmarkModel_->bookmark_bar_node() == node) | 2569 if (bookmarkModel_->bookmark_bar_node() == node) |
| 2741 return self; | 2570 return self; |
| 2742 return [folderController_ controllerForNode:node]; | 2571 return nil; |
| 2743 } | 2572 } |
| 2744 | 2573 |
| 2745 #pragma mark BookmarkButtonControllerProtocol | 2574 #pragma mark BookmarkButtonControllerProtocol |
| 2746 | 2575 |
| 2747 // NOT an override of a standard Cocoa call made to NSViewControllers. | 2576 // NOT an override of a standard Cocoa call made to NSViewControllers. |
| 2748 - (void)hookForEvent:(NSEvent*)theEvent { | 2577 - (void)hookForEvent:(NSEvent*)theEvent { |
| 2749 if ([self isEventAnExitEvent:theEvent]) | 2578 if ([self isEventAnExitEvent:theEvent]) |
| 2750 [self closeFolderAndStopTrackingMenus]; | 2579 [self closeFolderAndStopTrackingMenus]; |
| 2751 } | 2580 } |
| 2752 | 2581 |
| 2753 #pragma mark TestingAPI Only | 2582 #pragma mark TestingAPI Only |
| 2754 | 2583 |
| 2755 - (NSMenu*)buttonContextMenu { | 2584 - (NSMenu*)buttonContextMenu { |
| 2756 return buttonContextMenu_; | 2585 return buttonContextMenu_; |
| 2757 } | 2586 } |
| 2758 | 2587 |
| 2759 // Intentionally ignores ownership issues; used for testing and we try | 2588 // Intentionally ignores ownership issues; used for testing and we try |
| 2760 // to minimize touching the object passed in (likely a mock). | 2589 // to minimize touching the object passed in (likely a mock). |
| 2761 - (void)setButtonContextMenu:(id)menu { | 2590 - (void)setButtonContextMenu:(id)menu { |
| 2762 buttonContextMenu_ = menu; | 2591 buttonContextMenu_ = menu; |
| 2763 } | 2592 } |
| 2764 | 2593 |
| 2765 - (void)setIgnoreAnimations:(BOOL)ignore { | 2594 - (void)setIgnoreAnimations:(BOOL)ignore { |
| 2766 ignoreAnimations_ = ignore; | 2595 ignoreAnimations_ = ignore; |
| 2767 } | 2596 } |
| 2768 | 2597 |
| 2769 @end | 2598 @end |
| OLD | NEW |