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 |