Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm

Issue 8141003: [Mac] Restore the old bookmark menus now that the experiment is over. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/incognito_mode_prefs.h" 14 #include "chrome/browser/prefs/incognito_mode_prefs.h"
15 #include "chrome/browser/prefs/pref_service.h" 15 #include "chrome/browser/prefs/pref_service.h"
16 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/profiles/profile.h"
17 #import "chrome/browser/themes/theme_service.h" 17 #import "chrome/browser/themes/theme_service.h"
18 #import "chrome/browser/themes/theme_service_factory.h" 18 #import "chrome/browser/themes/theme_service_factory.h"
19 #include "chrome/browser/ui/browser.h" 19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_list.h" 20 #include "chrome/browser/ui/browser_list.h"
21 #import "chrome/browser/ui/cocoa/background_gradient_view.h" 21 #import "chrome/browser/ui/cocoa/background_gradient_view.h"
22 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h" 22 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h"
23 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" 23 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
24 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h"
24 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h" 25 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
25 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h" 26 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h"
26 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" 27 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
27 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h" 28 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
28 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h" 29 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h"
29 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" 30 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
30 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h" 31 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h"
31 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h" 32 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
32 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h" 33 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h"
33 #import "chrome/browser/ui/cocoa/browser_window_controller.h" 34 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 204
204 - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu; 205 - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu;
205 - (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu; 206 - (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu;
206 - (void)tagEmptyMenu:(NSMenu*)menu; 207 - (void)tagEmptyMenu:(NSMenu*)menu;
207 - (void)clearMenuTagMap; 208 - (void)clearMenuTagMap;
208 - (int)preferredHeight; 209 - (int)preferredHeight;
209 - (void)addNonBookmarkButtonsToView; 210 - (void)addNonBookmarkButtonsToView;
210 - (void)addButtonsToView; 211 - (void)addButtonsToView;
211 - (void)centerNoItemsLabel; 212 - (void)centerNoItemsLabel;
212 - (void)setNodeForBarMenu; 213 - (void)setNodeForBarMenu;
214 - (void)watchForExitEvent:(BOOL)watch;
213 - (void)resetAllButtonPositionsWithAnimation:(BOOL)animate; 215 - (void)resetAllButtonPositionsWithAnimation:(BOOL)animate;
214 - (BOOL)animationEnabled; 216 - (BOOL)animationEnabled;
215 217
216 @end 218 @end
217 219
218 @implementation BookmarkBarController 220 @implementation BookmarkBarController
219 221
220 @synthesize visualState = visualState_; 222 @synthesize visualState = visualState_;
221 @synthesize lastVisualState = lastVisualState_; 223 @synthesize lastVisualState = lastVisualState_;
222 @synthesize delegate = delegate_; 224 @synthesize delegate = delegate_;
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 320
319 // For safety, make sure the buttons can no longer call us. 321 // For safety, make sure the buttons can no longer call us.
320 for (BookmarkButton* button in buttons_.get()) { 322 for (BookmarkButton* button in buttons_.get()) {
321 [button setDelegate:nil]; 323 [button setDelegate:nil];
322 [button setTarget:nil]; 324 [button setTarget:nil];
323 [button setAction:nil]; 325 [button setAction:nil];
324 } 326 }
325 327
326 bridge_.reset(NULL); 328 bridge_.reset(NULL);
327 [[NSNotificationCenter defaultCenter] removeObserver:self]; 329 [[NSNotificationCenter defaultCenter] removeObserver:self];
330 [self watchForExitEvent:NO];
328 [super dealloc]; 331 [super dealloc];
329 } 332 }
330 333
331 - (void)awakeFromNib { 334 - (void)awakeFromNib {
332 // We default to NOT open, which means height=0. 335 // We default to NOT open, which means height=0.
333 DCHECK([[self view] isHidden]); // Hidden so it's OK to change. 336 DCHECK([[self view] isHidden]); // Hidden so it's OK to change.
334 337
335 // Set our initial height to zero, since that is what the superview 338 // Set our initial height to zero, since that is what the superview
336 // expects. We will resize ourselves open later if needed. 339 // expects. We will resize ourselves open later if needed.
337 [[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)]; 340 [[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)];
(...skipping 21 matching lines...) Expand all
359 362
360 // When resized we may need to add new buttons, or remove them (if 363 // When resized we may need to add new buttons, or remove them (if
361 // no longer visible), or add/remove the "off the side" menu. 364 // no longer visible), or add/remove the "off the side" menu.
362 [[self view] setPostsFrameChangedNotifications:YES]; 365 [[self view] setPostsFrameChangedNotifications:YES];
363 [[NSNotificationCenter defaultCenter] 366 [[NSNotificationCenter defaultCenter]
364 addObserver:self 367 addObserver:self
365 selector:@selector(frameDidChange) 368 selector:@selector(frameDidChange)
366 name:NSViewFrameDidChangeNotification 369 name:NSViewFrameDidChangeNotification
367 object:[self view]]; 370 object:[self view]];
368 371
372 // Watch for things going to or from fullscreen.
373 [[NSNotificationCenter defaultCenter]
374 addObserver:self
375 selector:@selector(willEnterOrLeaveFullscreen:)
376 name:kWillEnterFullscreenNotification
377 object:nil];
378 [[NSNotificationCenter defaultCenter]
379 addObserver:self
380 selector:@selector(willEnterOrLeaveFullscreen:)
381 name:kWillLeaveFullscreenNotification
382 object:nil];
383
369 // Don't pass ourself along (as 'self') until our init is completely 384 // Don't pass ourself along (as 'self') until our init is completely
370 // done. Thus, this call is (almost) last. 385 // done. Thus, this call is (almost) last.
371 bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_)); 386 bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_));
372 } 387 }
373 388
374 // Called by our main view (a BookmarkBarView) when it gets moved to a 389 // Called by our main view (a BookmarkBarView) when it gets moved to a
375 // window. We perform operations which need to know the relevant 390 // window. We perform operations which need to know the relevant
376 // window (e.g. watch for a window close) so they can't be performed 391 // window (e.g. watch for a window close) so they can't be performed
377 // earlier (such as in awakeFromNib). 392 // earlier (such as in awakeFromNib).
378 - (void)viewDidMoveToWindow { 393 - (void)viewDidMoveToWindow {
(...skipping 10 matching lines...) Expand all
389 [defaultCenter addObserver:self 404 [defaultCenter addObserver:self
390 selector:@selector(parentWindowWillClose:) 405 selector:@selector(parentWindowWillClose:)
391 name:NSWindowWillCloseNotification 406 name:NSWindowWillCloseNotification
392 object:[[self view] window]]; 407 object:[[self view] window]];
393 [defaultCenter addObserver:self 408 [defaultCenter addObserver:self
394 selector:@selector(parentWindowDidResignMain:) 409 selector:@selector(parentWindowDidResignMain:)
395 name:NSWindowDidResignMainNotification 410 name:NSWindowDidResignMainNotification
396 object:[[self view] window]]; 411 object:[[self view] window]];
397 } 412 }
398 413
414 // When going fullscreen we can run into trouble. Our view is removed
415 // from the non-fullscreen window before the non-fullscreen window
416 // loses key, so our parentDidResignKey: callback never gets called.
417 // In addition, a bookmark folder controller needs to be autoreleased
418 // (in case it's in the event chain when closed), but the release
419 // implicitly needs to happen while it's connected to the original
420 // (non-fullscreen) window to "unlock bar visibility". Such a
421 // contract isn't honored when going fullscreen with the menu option
422 // (not with the keyboard shortcut). We fake it as best we can here.
423 // We have a similar problem leaving fullscreen.
424 - (void)willEnterOrLeaveFullscreen:(NSNotification*)notification {
425 if (folderController_) {
426 [self childFolderWillClose:folderController_];
427 [self closeFolderAndStopTrackingMenus];
428 }
429 }
430
399 // NSNotificationCenter callback. 431 // NSNotificationCenter callback.
400 - (void)parentWindowWillClose:(NSNotification*)notification { 432 - (void)parentWindowWillClose:(NSNotification*)notification {
401 [self closeFolderAndStopTrackingMenus]; 433 [self closeFolderAndStopTrackingMenus];
402 } 434 }
403 435
404 // NSNotificationCenter callback. 436 // NSNotificationCenter callback.
405 - (void)parentWindowDidResignMain:(NSNotification*)notification { 437 - (void)parentWindowDidResignMain:(NSNotification*)notification {
406 [self closeFolderAndStopTrackingMenus]; 438 [self closeFolderAndStopTrackingMenus];
407 } 439 }
408 440
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 if (node == nil || 541 if (node == nil ||
510 node == bookmarkModel_->bookmark_bar_node() || 542 node == bookmarkModel_->bookmark_bar_node() ||
511 node == bookmarkModel_->other_node() || 543 node == bookmarkModel_->other_node() ||
512 node == bookmarkModel_->synced_node()) 544 node == bookmarkModel_->synced_node())
513 return NO; 545 return NO;
514 return YES; 546 return YES;
515 } 547 }
516 548
517 #pragma mark Actions 549 #pragma mark Actions
518 550
551 // Helper methods called on the main thread by runMenuFlashThread.
552
553 - (void)setButtonFlashStateOn:(id)sender {
554 [sender highlight:YES];
555 }
556
557 - (void)setButtonFlashStateOff:(id)sender {
558 [sender highlight:NO];
559 }
560
561 -(void)cleanupAfterMenuFlashThread:(id)sender {
562 [self closeFolderAndStopTrackingMenus];
563
564 // Items retained by doMenuFlashOnSeparateThread below.
565 [sender release];
566 [self release];
567 }
568
569 // End runMenuFlashThread helper methods.
570
571 // This call is invoked only by doMenuFlashOnSeparateThread below.
572 // It makes the selected BookmarkButton (which is masquerading as a menu item)
573 // flash a few times to give confirmation feedback, then it closes the menu.
574 // It spends all its time sleeping or scheduling UI work on the main thread.
575 - (void)runMenuFlashThread:(id)sender {
576
577 // Check this is not running on the main thread, as it sleeps.
578 DCHECK(![NSThread isMainThread]);
579
580 // Duration of flash phases and number of flashes designed to evoke a
581 // slightly retro "more mac-like than the Mac" feel.
582 // Current Cocoa UI has a barely perceptible flash,probably because Apple
583 // doesn't fire the action til after the animation and so there's a hurry.
584 // As this code is fully asynchronous, it can take its time.
585 const float kBBOnFlashTime = 0.08;
586 const float kBBOffFlashTime = 0.08;
587 const int kBookmarkButtonMenuFlashes = 3;
588
589 for (int count = 0 ; count < kBookmarkButtonMenuFlashes ; count++) {
590 [self performSelectorOnMainThread:@selector(setButtonFlashStateOn:)
591 withObject:sender
592 waitUntilDone:NO];
593 [NSThread sleepForTimeInterval:kBBOnFlashTime];
594 [self performSelectorOnMainThread:@selector(setButtonFlashStateOff:)
595 withObject:sender
596 waitUntilDone:NO];
597 [NSThread sleepForTimeInterval:kBBOffFlashTime];
598 }
599 [self performSelectorOnMainThread:@selector(cleanupAfterMenuFlashThread:)
600 withObject:sender
601 waitUntilDone:NO];
602 }
603
604 // Non-blocking call which starts the process to make the selected menu item
605 // flash a few times to give confirmation feedback, after which it closes the
606 // menu. The item is of course actually a BookmarkButton masquerading as a menu
607 // item).
608 - (void)doMenuFlashOnSeparateThread:(id)sender {
609
610 // Ensure that self and sender don't go away before the animation completes.
611 // These retains are balanced in cleanupAfterMenuFlashThread above.
612 [self retain];
613 [sender retain];
614 [NSThread detachNewThreadSelector:@selector(runMenuFlashThread:)
615 toTarget:self
616 withObject:sender];
617 }
618
519 - (IBAction)openBookmark:(id)sender { 619 - (IBAction)openBookmark:(id)sender {
520 BOOL isMenuItem = [sender isFolder]; 620 BOOL isMenuItem = [[sender cell] isFolderButtonCell];
521 BOOL animate = isMenuItem && [self animationEnabled]; 621 BOOL animate = isMenuItem && [self animationEnabled];
622 if (animate)
623 [self doMenuFlashOnSeparateThread:sender];
522 DCHECK([sender respondsToSelector:@selector(bookmarkNode)]); 624 DCHECK([sender respondsToSelector:@selector(bookmarkNode)]);
523 const BookmarkNode* node = [sender bookmarkNode]; 625 const BookmarkNode* node = [sender bookmarkNode];
524 WindowOpenDisposition disposition = 626 WindowOpenDisposition disposition =
525 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); 627 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
526 RecordAppLaunch(browser_->profile(), node->url()); 628 RecordAppLaunch(browser_->profile(), node->url());
527 [self openURL:node->url() disposition:disposition]; 629 [self openURL:node->url() disposition:disposition];
528 630
529 if (!animate) 631 if (!animate)
530 [self closeFolderAndStopTrackingMenus]; 632 [self closeFolderAndStopTrackingMenus];
531 } 633 }
532 634
533 // Common function to open a bookmark folder of any type. 635 // Common function to open a bookmark folder of any type.
534 - (void)openBookmarkFolder:(id)sender { 636 - (void)openBookmarkFolder:(id)sender {
535 DCHECK([sender isKindOfClass:[BookmarkButton class]]); 637 DCHECK([sender isKindOfClass:[BookmarkButton class]]);
536 DCHECK([[sender cell] isKindOfClass:[BookmarkButtonCell class]]); 638 DCHECK([[sender cell] isKindOfClass:[BookmarkButtonCell class]]);
537 639
538 showFolderMenus_ = !showFolderMenus_; 640 showFolderMenus_ = !showFolderMenus_;
539 641
642 if (sender == offTheSideButton_)
643 [[sender cell] setStartingChildIndex:displayedButtonCount_];
644
540 // Toggle presentation of bar folder menus. 645 // Toggle presentation of bar folder menus.
541 [folderTarget_ openBookmarkFolderFromButton:sender]; 646 [folderTarget_ openBookmarkFolderFromButton:sender];
542 } 647 }
543 648
544 649
545 // Click on a bookmark folder button. 650 // Click on a bookmark folder button.
546 - (IBAction)openBookmarkFolderFromButton:(id)sender { 651 - (IBAction)openBookmarkFolderFromButton:(id)sender {
547 [self openBookmarkFolder:sender]; 652 [self openBookmarkFolder:sender];
548 } 653 }
549 654
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
747 bookmarks::kBookmarkHorizontalPadding)); 852 bookmarks::kBookmarkHorizontalPadding));
748 } else { 853 } else {
749 frame.origin.x = (NSMaxX([otherBookmarksButton_ frame]) - frame.size.width); 854 frame.origin.x = (NSMaxX([otherBookmarksButton_ frame]) - frame.size.width);
750 } 855 }
751 [offTheSideButton_ setFrame:frame]; 856 [offTheSideButton_ setFrame:frame];
752 } 857 }
753 858
754 // Configure the off-the-side button (e.g. specify the node range, 859 // Configure the off-the-side button (e.g. specify the node range,
755 // check if we should enable or disable it, etc). 860 // check if we should enable or disable it, etc).
756 - (void)configureOffTheSideButtonContentsAndVisibility { 861 - (void)configureOffTheSideButtonContentsAndVisibility {
862 // If deleting a button while off-the-side is open, buttons may be
863 // promoted from off-the-side to the bar. Accomodate.
864 if (folderController_ &&
865 ([folderController_ parentButton] == offTheSideButton_)) {
866 [folderController_ reconfigureMenu];
867 }
868
869 [[offTheSideButton_ cell] setStartingChildIndex:displayedButtonCount_];
757 [[offTheSideButton_ cell] 870 [[offTheSideButton_ cell]
758 setBookmarkNode:bookmarkModel_->bookmark_bar_node()]; 871 setBookmarkNode:bookmarkModel_->bookmark_bar_node()];
759 int bookmarkChildren = bookmarkModel_->bookmark_bar_node()->child_count(); 872 int bookmarkChildren = bookmarkModel_->bookmark_bar_node()->child_count();
760 if (bookmarkChildren > displayedButtonCount_) { 873 if (bookmarkChildren > displayedButtonCount_) {
761 [offTheSideButton_ setHidden:NO]; 874 [offTheSideButton_ setHidden:NO];
762 } else { 875 } else {
763 // If we just deleted the last item in an off-the-side menu so the 876 // If we just deleted the last item in an off-the-side menu so the
764 // button will be going away, make sure the menu goes away. 877 // button will be going away, make sure the menu goes away.
765 if (folderController_ && 878 if (folderController_ &&
766 ([folderController_ parentButton] == offTheSideButton_)) 879 ([folderController_ parentButton] == offTheSideButton_))
767 [self closeAllBookmarkFolders]; 880 [self closeAllBookmarkFolders];
768 // (And hide the button, too.) 881 // (And hide the button, too.)
769 [offTheSideButton_ setHidden:YES]; 882 [offTheSideButton_ setHidden:YES];
770 } 883 }
771 } 884 }
772 885
886 // Main menubar observation code, so we can know to close our fake menus if the
887 // user clicks on the actual menubar, as multiple unconnected menus sharing
888 // the screen looks weird.
889 // Needed because the hookForEvent method doesn't see the click on the menubar.
890
891 // Gets called when the menubar is clicked.
892 - (void)begunTracking:(NSNotification *)notification {
893 [self closeFolderAndStopTrackingMenus];
894 }
895
896 // Install the callback.
897 - (void)startObservingMenubar {
898 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
899 [nc addObserver:self
900 selector:@selector(begunTracking:)
901 name:NSMenuDidBeginTrackingNotification
902 object:[NSApp mainMenu]];
903 }
904
905 // Remove the callback.
906 - (void)stopObservingMenubar {
907 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
908 [nc removeObserver:self
909 name:NSMenuDidBeginTrackingNotification
910 object:[NSApp mainMenu]];
911 }
912
913 // End of menubar observation code.
914
915 // Begin (or end) watching for a click outside this window. Unlike
916 // normal NSWindows, bookmark folder "fake menu" windows do not become
917 // key or main. Thus, traditional notification (e.g. WillResignKey)
918 // won't work. Our strategy is to watch (at the app level) for a
919 // "click outside" these windows to detect when they logically lose
920 // focus.
921 - (void)watchForExitEvent:(BOOL)watch {
922 CrApplication* app = static_cast<CrApplication*>([NSApplication
923 sharedApplication]);
924 DCHECK([app isKindOfClass:[CrApplication class]]);
925 if (watch) {
926 if (!watchingForExitEvent_) {
927 [app addEventHook:self];
928 [self startObservingMenubar];
929 }
930 } else {
931 if (watchingForExitEvent_) {
932 [app removeEventHook:self];
933 [self stopObservingMenubar];
934 }
935 }
936 watchingForExitEvent_ = watch;
937 }
938
773 // Keep the "no items" label centered in response to a frame size change. 939 // Keep the "no items" label centered in response to a frame size change.
774 - (void)centerNoItemsLabel { 940 - (void)centerNoItemsLabel {
775 // Note that this computation is done in the parent's coordinate system, 941 // Note that this computation is done in the parent's coordinate system,
776 // which is unflipped. Also, we want the label to be a fixed distance from 942 // which is unflipped. Also, we want the label to be a fixed distance from
777 // the bottom, so that it slides up properly (on animating to hidden). 943 // the bottom, so that it slides up properly (on animating to hidden).
778 // The textfield sits in the itemcontainer, so to center it we maintain 944 // The textfield sits in the itemcontainer, so to center it we maintain
779 // equal vertical padding on the top and bottom. 945 // equal vertical padding on the top and bottom.
780 int yoffset = (NSHeight([[buttonView_ noItemTextfield] frame]) - 946 int yoffset = (NSHeight([[buttonView_ noItemTextfield] frame]) -
781 NSHeight([[buttonView_ noItemContainer] frame])) / 2; 947 NSHeight([[buttonView_ noItemContainer] frame])) / 2;
782 [[buttonView_ noItemContainer] setFrameOrigin:NSMakePoint(0, yoffset)]; 948 [[buttonView_ noItemContainer] setFrameOrigin:NSMakePoint(0, yoffset)];
(...skipping 851 matching lines...) Expand 10 before | Expand all | Expand 10 after
1634 NSColor* color = 1800 NSColor* color =
1635 themeProvider->GetNSColor(ThemeService::COLOR_BOOKMARK_TEXT, 1801 themeProvider->GetNSColor(ThemeService::COLOR_BOOKMARK_TEXT,
1636 true); 1802 true);
1637 for (BookmarkButton* button in buttons_.get()) { 1803 for (BookmarkButton* button in buttons_.get()) {
1638 BookmarkButtonCell* cell = [button cell]; 1804 BookmarkButtonCell* cell = [button cell];
1639 [cell setTextColor:color]; 1805 [cell setTextColor:color];
1640 } 1806 }
1641 [[otherBookmarksButton_ cell] setTextColor:color]; 1807 [[otherBookmarksButton_ cell] setTextColor:color];
1642 } 1808 }
1643 1809
1810 // Return YES if the event indicates an exit from the bookmark bar
1811 // folder menus. E.g. "click outside" of the area we are watching.
1812 // At this time we are watching the area that includes all popup
1813 // bookmark folder windows.
1814 - (BOOL)isEventAnExitEvent:(NSEvent*)event {
1815 NSWindow* eventWindow = [event window];
1816 NSWindow* myWindow = [[self view] window];
1817 switch ([event type]) {
1818 case NSLeftMouseDown:
1819 case NSRightMouseDown:
1820 // If the click is in my window but NOT in the bookmark bar, consider
1821 // it a click 'outside'. Clicks directly on an active button (i.e. one
1822 // that is a folder and for which its folder menu is showing) are 'in'.
1823 // All other clicks on the bookmarks bar are counted as 'outside'
1824 // because they should close any open bookmark folder menu.
1825 if (eventWindow == myWindow) {
1826 NSView* hitView =
1827 [[eventWindow contentView] hitTest:[event locationInWindow]];
1828 if (hitView == [folderController_ parentButton])
1829 return NO;
1830 if (![hitView isDescendantOf:[self view]] || hitView == buttonView_)
1831 return YES;
1832 }
1833 // If a click in a bookmark bar folder window and that isn't
1834 // one of my bookmark bar folders, YES is click outside.
1835 if (![eventWindow isKindOfClass:[BookmarkBarFolderWindow
1836 class]]) {
1837 return YES;
1838 }
1839 break;
1840 case NSKeyDown: {
1841 // Event hooks often see the same keydown event twice due to the way key
1842 // events get dispatched and redispatched, so ignore if this keydown
1843 // event has the EXACT same timestamp as the previous keydown.
1844 static NSTimeInterval lastKeyDownEventTime;
1845 NSTimeInterval thisTime = [event timestamp];
1846 if (lastKeyDownEventTime != thisTime) {
1847 lastKeyDownEventTime = thisTime;
1848 if ([event modifierFlags] & NSCommandKeyMask)
1849 return YES;
1850 else if (folderController_)
1851 return [folderController_ handleInputText:[event characters]];
1852 }
1853 return NO;
1854 }
1855 case NSKeyUp:
1856 return NO;
1857 case NSLeftMouseDragged:
1858 // We can get here with the following sequence:
1859 // - open a bookmark folder
1860 // - right-click (and unclick) on it to open context menu
1861 // - move mouse to window titlebar then click-drag it by the titlebar
1862 // http://crbug.com/49333
1863 return NO;
1864 default:
1865 break;
1866 }
1867 return NO;
1868 }
1869
1644 #pragma mark Drag & Drop 1870 #pragma mark Drag & Drop
1645 1871
1646 // Find something like std::is_between<T>? I can't believe one doesn't exist. 1872 // Find something like std::is_between<T>? I can't believe one doesn't exist.
1647 static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { 1873 static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
1648 return ((value >= low) && (value <= high)); 1874 return ((value >= low) && (value <= high));
1649 } 1875 }
1650 1876
1651 // Return the proposed drop target for a hover open button from the 1877 // Return the proposed drop target for a hover open button from the
1652 // given array, or nil if none. We use this for distinguishing 1878 // given array, or nil if none. We use this for distinguishing
1653 // between a hover-open candidate or drop-indicator draw. 1879 // between a hover-open candidate or drop-indicator draw.
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after
1972 if (cellnode == node) { 2198 if (cellnode == node) {
1973 [[button cell] setBookmarkCellText:[button title] 2199 [[button cell] setBookmarkCellText:[button title]
1974 image:[self faviconForNode:node]]; 2200 image:[self faviconForNode:node]];
1975 // Adding an image means we might need more room for the 2201 // Adding an image means we might need more room for the
1976 // bookmark. Test for it by growing the button (if needed) 2202 // bookmark. Test for it by growing the button (if needed)
1977 // and shifting everything else over. 2203 // and shifting everything else over.
1978 [self checkForBookmarkButtonGrowth:button]; 2204 [self checkForBookmarkButtonGrowth:button];
1979 return; 2205 return;
1980 } 2206 }
1981 } 2207 }
2208
2209 if (folderController_)
2210 [folderController_ faviconLoadedForNode:node];
1982 } 2211 }
1983 2212
1984 // TODO(jrg): for now this is brute force. 2213 // TODO(jrg): for now this is brute force.
1985 - (void)nodeChildrenReordered:(BookmarkModel*)model 2214 - (void)nodeChildrenReordered:(BookmarkModel*)model
1986 node:(const BookmarkNode*)node { 2215 node:(const BookmarkNode*)node {
1987 [self loaded:model]; 2216 [self loaded:model];
1988 } 2217 }
1989 2218
1990 #pragma mark BookmarkBarState Protocol 2219 #pragma mark BookmarkBarState Protocol
1991 2220
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
2080 // a subfolder menu. 2309 // a subfolder menu.
2081 if (!showFolderMenus_) 2310 if (!showFolderMenus_)
2082 return; 2311 return;
2083 2312
2084 // From here down: same logic as BookmarkBarFolderController. 2313 // From here down: same logic as BookmarkBarFolderController.
2085 // TODO(jrg): find a way to share these 4 non-comment lines? 2314 // TODO(jrg): find a way to share these 4 non-comment lines?
2086 // http://crbug.com/35966 2315 // http://crbug.com/35966
2087 // If already opened, then we exited but re-entered the button, so do nothing. 2316 // If already opened, then we exited but re-entered the button, so do nothing.
2088 if ([folderController_ parentButton] == sender) 2317 if ([folderController_ parentButton] == sender)
2089 return; 2318 return;
2319 // Else open a new one if it makes sense to do so.
2320 if ([sender bookmarkNode]->is_folder()) {
2321 // Update |hoverButton_| so that it corresponds to the open folder.
2322 hoverButton_.reset([sender retain]);
2323 [folderTarget_ openBookmarkFolderFromButton:sender];
2324 } else {
2325 // We're over a non-folder bookmark so close any old folders.
2326 [folderController_ close];
2327 folderController_ = nil;
2328 }
2090 } 2329 }
2091 2330
2092 // BookmarkButtonDelegate protocol implementation. 2331 // BookmarkButtonDelegate protocol implementation.
2093 - (void)mouseExitedButton:(id)sender event:(NSEvent*)event { 2332 - (void)mouseExitedButton:(id)sender event:(NSEvent*)event {
2094 // Don't care; do nothing. 2333 // Don't care; do nothing.
2095 // This is different behavior that the folder menus. 2334 // This is different behavior that the folder menus.
2096 } 2335 }
2097 2336
2098 - (NSWindow*)browserWindow { 2337 - (NSWindow*)browserWindow {
2099 return [[self view] window]; 2338 return [[self view] window];
(...skipping 20 matching lines...) Expand all
2120 [button setHidden:NO]; 2359 [button setHidden:NO];
2121 [self resetAllButtonPositionsWithAnimation:YES]; 2360 [self resetAllButtonPositionsWithAnimation:YES];
2122 } 2361 }
2123 2362
2124 2363
2125 #pragma mark BookmarkButtonControllerProtocol 2364 #pragma mark BookmarkButtonControllerProtocol
2126 2365
2127 // Close all bookmark folders. "Folder" here is the fake menu for 2366 // Close all bookmark folders. "Folder" here is the fake menu for
2128 // bookmark folders, not a button context menu. 2367 // bookmark folders, not a button context menu.
2129 - (void)closeAllBookmarkFolders { 2368 - (void)closeAllBookmarkFolders {
2130 [folderController_ closeMenu]; 2369 [self watchForExitEvent:NO];
2370 [folderController_ close];
2131 folderController_ = nil; 2371 folderController_ = nil;
2132 } 2372 }
2133 2373
2134 - (void)closeBookmarkFolder:(id)sender { 2374 - (void)closeBookmarkFolder:(id)sender {
2135 // We're the top level, so close one means close them all. 2375 // We're the top level, so close one means close them all.
2136 [self closeAllBookmarkFolders]; 2376 [self closeAllBookmarkFolders];
2137 } 2377 }
2138 2378
2139 - (BookmarkModel*)bookmarkModel { 2379 - (BookmarkModel*)bookmarkModel {
2140 return bookmarkModel_; 2380 return bookmarkModel_;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2175 target]]; 2415 target]];
2176 // Unlike BookmarkBarFolderController, we do not delay the close 2416 // Unlike BookmarkBarFolderController, we do not delay the close
2177 // of the previous one. Given the lack of diagonal movement, 2417 // of the previous one. Given the lack of diagonal movement,
2178 // there is no need, and it feels awkward to do so. See 2418 // there is no need, and it feels awkward to do so. See
2179 // comments about kDragHoverCloseDelay in 2419 // comments about kDragHoverCloseDelay in
2180 // bookmark_bar_folder_controller.mm for more details. 2420 // bookmark_bar_folder_controller.mm for more details.
2181 [[hoverButton_ target] closeBookmarkFolder:hoverButton_]; 2421 [[hoverButton_ target] closeBookmarkFolder:hoverButton_];
2182 hoverButton_.reset(); 2422 hoverButton_.reset();
2183 } 2423 }
2184 hoverButton_.reset([button retain]); 2424 hoverButton_.reset([button retain]);
2425 DCHECK([[hoverButton_ target]
2426 respondsToSelector:@selector(openBookmarkFolderFromButton:)]);
2427 [[hoverButton_ target]
2428 performSelector:@selector(openBookmarkFolderFromButton:)
2429 withObject:hoverButton_
2430 afterDelay:bookmarks::kDragHoverOpenDelay
2431 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
2185 } 2432 }
2186 if (!button) { 2433 if (!button) {
2187 if (hoverButton_) { 2434 if (hoverButton_) {
2435 [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_ target]];
2188 [[hoverButton_ target] closeBookmarkFolder:hoverButton_]; 2436 [[hoverButton_ target] closeBookmarkFolder:hoverButton_];
2189 hoverButton_.reset(); 2437 hoverButton_.reset();
2190 } 2438 }
2191 } 2439 }
2192 2440
2193 // Thrown away but kept to be consistent with the draggingEntered: interface. 2441 // Thrown away but kept to be consistent with the draggingEntered: interface.
2194 return NSDragOperationMove; 2442 return NSDragOperationMove;
2195 } 2443 }
2196 2444
2197 - (void)draggingExited:(id<NSDraggingInfo>)info { 2445 - (void)draggingExited:(id<NSDraggingInfo>)info {
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
2282 } else { 2530 } else {
2283 x = 0.5 * bookmarks::kBookmarkHorizontalPadding; 2531 x = 0.5 * bookmarks::kBookmarkHorizontalPadding;
2284 } 2532 }
2285 } else { 2533 } else {
2286 NOTREACHED(); 2534 NOTREACHED();
2287 } 2535 }
2288 2536
2289 return x; 2537 return x;
2290 } 2538 }
2291 2539
2540 - (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
2541 // If the bookmarkbar is not in detached mode, lock bar visibility, forcing
2542 // the overlay to stay open when in fullscreen mode.
2543 if (![self isInState:bookmarks::kDetachedState] &&
2544 ![self isAnimatingToState:bookmarks::kDetachedState]) {
2545 BrowserWindowController* browserController =
2546 [BrowserWindowController browserWindowControllerForView:[self view]];
2547 [browserController lockBarVisibilityForOwner:child
2548 withAnimation:NO
2549 delay:NO];
2550 }
2551 }
2552
2553 - (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
2554 // Release bar visibility, allowing the overlay to close if in fullscreen
2555 // mode.
2556 BrowserWindowController* browserController =
2557 [BrowserWindowController browserWindowControllerForView:[self view]];
2558 [browserController releaseBarVisibilityForOwner:child
2559 withAnimation:NO
2560 delay:NO];
2561 }
2562
2292 // Add a new folder controller as triggered by the given folder button. 2563 // Add a new folder controller as triggered by the given folder button.
2293 - (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton { 2564 - (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton {
2294 2565
2295 // If doing a close/open, make sure the fullscreen chrome doesn't 2566 // If doing a close/open, make sure the fullscreen chrome doesn't
2296 // have a chance to begin animating away in the middle of things. 2567 // have a chance to begin animating away in the middle of things.
2297 BrowserWindowController* browserController = 2568 BrowserWindowController* browserController =
2298 [BrowserWindowController browserWindowControllerForView:[self view]]; 2569 [BrowserWindowController browserWindowControllerForView:[self view]];
2299 // Confirm we're not re-locking with ourself as an owner before locking. 2570 // Confirm we're not re-locking with ourself as an owner before locking.
2300 DCHECK([browserController isBarVisibilityLockedForOwner:self] == NO); 2571 DCHECK([browserController isBarVisibilityLockedForOwner:self] == NO);
2301 [browserController lockBarVisibilityForOwner:self 2572 [browserController lockBarVisibilityForOwner:self
2302 withAnimation:NO 2573 withAnimation:NO
2303 delay:NO]; 2574 delay:NO];
2304 2575
2305 if (folderController_) 2576 if (folderController_)
2306 [self closeAllBookmarkFolders]; 2577 [self closeAllBookmarkFolders];
2307 2578
2308 // Folder controller, like many window controllers, owns itself. 2579 // Folder controller, like many window controllers, owns itself.
2309 folderController_ = 2580 folderController_ =
2310 [[BookmarkBarFolderController alloc] initWithParentButton:parentButton 2581 [[BookmarkBarFolderController alloc] initWithParentButton:parentButton
2311 bookmarkModel:bookmarkModel_ 2582 parentController:nil
2312 barController:self]; 2583 barController:self];
2313 [folderController_ autorelease]; 2584 [folderController_ showWindow:self];
2314 2585
2315 // If this is for the off-the-side menu, set the display count. 2586 // Only BookmarkBarController has this; the
2316 if (parentButton == offTheSideButton_) 2587 // BookmarkBarFolderController does not.
2317 [folderController_ setOffTheSideNodeStartIndex:displayedButtonCount_]; 2588 [self watchForExitEvent:YES];
2318
2319 [folderController_ openMenu];
2320 2589
2321 // No longer need to hold the lock; the folderController_ now owns it. 2590 // No longer need to hold the lock; the folderController_ now owns it.
2322 [browserController releaseBarVisibilityForOwner:self 2591 [browserController releaseBarVisibilityForOwner:self
2323 withAnimation:NO 2592 withAnimation:NO
2324 delay:NO]; 2593 delay:NO];
2325 } 2594 }
2326 2595
2327 - (void)openAll:(const BookmarkNode*)node 2596 - (void)openAll:(const BookmarkNode*)node
2328 disposition:(WindowOpenDisposition)disposition { 2597 disposition:(WindowOpenDisposition)disposition {
2329 [self closeFolderAndStopTrackingMenus]; 2598 [self closeFolderAndStopTrackingMenus];
(...skipping 20 matching lines...) Expand all
2350 ++displayedButtonCount_; 2619 ++displayedButtonCount_;
2351 [buttons_ insertObject:newButton atIndex:buttonIndex]; 2620 [buttons_ insertObject:newButton atIndex:buttonIndex];
2352 [buttonView_ addSubview:newButton]; 2621 [buttonView_ addSubview:newButton];
2353 [self resetAllButtonPositionsWithAnimation:NO]; 2622 [self resetAllButtonPositionsWithAnimation:NO];
2354 // See if any buttons need to be pushed off to or brought in from the side. 2623 // See if any buttons need to be pushed off to or brought in from the side.
2355 [self reconfigureBookmarkBar]; 2624 [self reconfigureBookmarkBar];
2356 } else { 2625 } else {
2357 // A button from somewhere else (not the bar) is being moved to the 2626 // A button from somewhere else (not the bar) is being moved to the
2358 // off-the-side so insure it gets redrawn if its showing. 2627 // off-the-side so insure it gets redrawn if its showing.
2359 [self reconfigureBookmarkBar]; 2628 [self reconfigureBookmarkBar];
2629 [folderController_ reconfigureMenu];
2360 } 2630 }
2361 } 2631 }
2362 2632
2363 // TODO(mrossetti): Duplicate code with BookmarkBarFolderController. 2633 // TODO(mrossetti): Duplicate code with BookmarkBarFolderController.
2364 // http://crbug.com/35966 2634 // http://crbug.com/35966
2365 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { 2635 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
2366 DCHECK([urls count] == [titles count]); 2636 DCHECK([urls count] == [titles count]);
2367 BOOL nodesWereAdded = NO; 2637 BOOL nodesWereAdded = NO;
2368 // Figure out where these new bookmarks nodes are to be added. 2638 // Figure out where these new bookmarks nodes are to be added.
2369 BookmarkButton* button = [self buttonForDroppingOnAtPoint:point]; 2639 BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
2417 [movedButton setHidden:NO]; 2687 [movedButton setHidden:NO];
2418 [self resetAllButtonPositionsWithAnimation:NO]; 2688 [self resetAllButtonPositionsWithAnimation:NO];
2419 } else if (fromIndex < buttonCount) { 2689 } else if (fromIndex < buttonCount) {
2420 // A button is being removed from the bar and added to off-the-side. 2690 // A button is being removed from the bar and added to off-the-side.
2421 // By now the node has already been inserted into the model so the 2691 // By now the node has already been inserted into the model so the
2422 // button to be added is represented by |toIndex|. Things get 2692 // button to be added is represented by |toIndex|. Things get
2423 // complicated because the off-the-side is showing and must be redrawn 2693 // complicated because the off-the-side is showing and must be redrawn
2424 // while possibly re-laying out the bookmark bar. 2694 // while possibly re-laying out the bookmark bar.
2425 [self removeButton:fromIndex animate:NO]; 2695 [self removeButton:fromIndex animate:NO];
2426 [self reconfigureBookmarkBar]; 2696 [self reconfigureBookmarkBar];
2697 [folderController_ reconfigureMenu];
2427 } else if (toIndex < buttonCount) { 2698 } else if (toIndex < buttonCount) {
2428 // A button is being added to the bar and removed from off-the-side. 2699 // A button is being added to the bar and removed from off-the-side.
2429 // By now the node has already been inserted into the model so the 2700 // By now the node has already been inserted into the model so the
2430 // button to be added is represented by |toIndex|. 2701 // button to be added is represented by |toIndex|.
2431 const BookmarkNode* node = bookmarkModel_->bookmark_bar_node(); 2702 const BookmarkNode* node = bookmarkModel_->bookmark_bar_node();
2432 const BookmarkNode* movedNode = node->GetChild(toIndex); 2703 const BookmarkNode* movedNode = node->GetChild(toIndex);
2433 DCHECK(movedNode); 2704 DCHECK(movedNode);
2434 [self addButtonForNode:movedNode atIndex:toIndex]; 2705 [self addButtonForNode:movedNode atIndex:toIndex];
2435 [self reconfigureBookmarkBar]; 2706 [self reconfigureBookmarkBar];
2707 } else {
2708 // A button is being moved within the off-the-side.
2709 fromIndex -= buttonCount;
2710 toIndex -= buttonCount;
2711 [folderController_ moveButtonFromIndex:fromIndex toIndex:toIndex];
2436 } 2712 }
2437 } 2713 }
2438 } 2714 }
2439 2715
2440 - (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate { 2716 - (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate {
2441 if (buttonIndex < (NSInteger)[buttons_ count]) { 2717 if (buttonIndex < (NSInteger)[buttons_ count]) {
2442 // The button being removed is showing in the bar. 2718 // The button being removed is showing in the bar.
2443 BookmarkButton* oldButton = [buttons_ objectAtIndex:buttonIndex]; 2719 BookmarkButton* oldButton = [buttons_ objectAtIndex:buttonIndex];
2444 if (oldButton == [folderController_ parentButton]) { 2720 if (oldButton == [folderController_ parentButton]) {
2445 // If we are deleting a button whose folder is currently open, close it! 2721 // If we are deleting a button whose folder is currently open, close it!
2446 [self closeAllBookmarkFolders]; 2722 [self closeAllBookmarkFolders];
2447 } 2723 }
2448 if (animate && !ignoreAnimations_ && [self isVisible] && 2724 if (animate && !ignoreAnimations_ && [self isVisible] &&
2449 [[self browserWindow] isMainWindow]) { 2725 [[self browserWindow] isMainWindow]) {
2450 NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation]; 2726 NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation];
2451 NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint, 2727 NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint,
2452 NSZeroSize, nil, nil, nil); 2728 NSZeroSize, nil, nil, nil);
2453 } 2729 }
2454 [oldButton setDelegate:nil]; 2730 [oldButton setDelegate:nil];
2455 [oldButton removeFromSuperview]; 2731 [oldButton removeFromSuperview];
2456 [buttons_ removeObjectAtIndex:buttonIndex]; 2732 [buttons_ removeObjectAtIndex:buttonIndex];
2457 --displayedButtonCount_; 2733 --displayedButtonCount_;
2458 [self resetAllButtonPositionsWithAnimation:YES]; 2734 [self resetAllButtonPositionsWithAnimation:YES];
2459 [self reconfigureBookmarkBar]; 2735 [self reconfigureBookmarkBar];
2736 } else if (folderController_ &&
2737 [folderController_ parentButton] == offTheSideButton_) {
2738 // The button being removed is in the OTS (off-the-side) and the OTS
2739 // menu is showing so we need to remove the button.
2740 NSInteger index = buttonIndex - displayedButtonCount_;
2741 [folderController_ removeButton:index animate:YES];
2460 } 2742 }
2461 } 2743 }
2462 2744
2463 - (id<BookmarkButtonControllerProtocol>)controllerForNode: 2745 - (id<BookmarkButtonControllerProtocol>)controllerForNode:
2464 (const BookmarkNode*)node { 2746 (const BookmarkNode*)node {
2465 // See if it's in the bar, then if it is in the hierarchy of visible 2747 // See if it's in the bar, then if it is in the hierarchy of visible
2466 // folder menus. 2748 // folder menus.
2467 if (bookmarkModel_->bookmark_bar_node() == node) 2749 if (bookmarkModel_->bookmark_bar_node() == node)
2468 return self; 2750 return self;
2469 return nil; 2751 return [folderController_ controllerForNode:node];
2752 }
2753
2754 #pragma mark BookmarkButtonControllerProtocol
2755
2756 // NOT an override of a standard Cocoa call made to NSViewControllers.
2757 - (void)hookForEvent:(NSEvent*)theEvent {
2758 if ([self isEventAnExitEvent:theEvent])
2759 [self closeFolderAndStopTrackingMenus];
2470 } 2760 }
2471 2761
2472 #pragma mark TestingAPI Only 2762 #pragma mark TestingAPI Only
2473 2763
2474 - (NSMenu*)buttonContextMenu { 2764 - (NSMenu*)buttonContextMenu {
2475 return buttonContextMenu_; 2765 return buttonContextMenu_;
2476 } 2766 }
2477 2767
2478 // Intentionally ignores ownership issues; used for testing and we try 2768 // Intentionally ignores ownership issues; used for testing and we try
2479 // to minimize touching the object passed in (likely a mock). 2769 // to minimize touching the object passed in (likely a mock).
2480 - (void)setButtonContextMenu:(id)menu { 2770 - (void)setButtonContextMenu:(id)menu {
2481 buttonContextMenu_ = menu; 2771 buttonContextMenu_ = menu;
2482 } 2772 }
2483 2773
2484 - (void)setIgnoreAnimations:(BOOL)ignore { 2774 - (void)setIgnoreAnimations:(BOOL)ignore {
2485 ignoreAnimations_ = ignore; 2775 ignoreAnimations_ = ignore;
2486 } 2776 }
2487 2777
2488 @end 2778 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698