1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h" 6 7 #include "base/strings/sys_string_conversions.h" 8 #include "chrome/app/chrome_command_ids.h" // IDC_BOOKMARK_MENU 9 #import "chrome/browser/app_controller_mac.h" 10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/ui/bookmarks/bookmark_utils.h" 12 #include "chrome/browser/ui/browser.h" 13 #include "chrome/browser/ui/browser_finder.h" 14 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h" 15 #import "chrome/browser/ui/cocoa/l10n_util.h" 16 #include "chrome/browser/ui/host_desktop.h" 17 #include "components/bookmarks/browser/bookmark_utils.h" 18 #include "content/public/browser/user_metrics.h" 19 #import "ui/base/cocoa/cocoa_base_utils.h" 20 #import "ui/base/cocoa/menu_controller.h" 21 22 using base::UserMetricsAction; 23 using content::OpenURLParams; 24 using content::Referrer; 25 26 namespace { 27 28 // Menus more than this many pixels wide will get trimmed 29 // TODO(jrg): ask UI dudes what a good value is. 30 const NSUInteger kMaximumMenuPixelsWide = 300; 31 32 } 33 34 @implementation BookmarkMenuCocoaController 35 36 + (NSString*)menuTitleForNode:(const BookmarkNode*)node { 37 base::string16 title = [MenuController elideMenuTitle:node->GetTitle() 38 toWidth:kMaximumMenuPixelsWide]; 39 return base::SysUTF16ToNSString(title); 40 } 41 42 + (NSString*)tooltipForNode:(const BookmarkNode*)node { 43 NSString* title = base::SysUTF16ToNSString(node->GetTitle()); 44 std::string urlString = node->url().possibly_invalid_spec(); 45 NSString* url = base::SysUTF8ToNSString(urlString); 46 return cocoa_l10n_util::TooltipForURLAndTitle(url, title); 47 } 48 49 - (id)initWithBridge:(BookmarkMenuBridge*)bridge 50 andMenu:(NSMenu*)menu { 51 if ((self = [super init])) { 52 bridge_ = bridge; 53 DCHECK(bridge_); 54 menu_ = menu; 55 [[self menu] setDelegate:self]; 56 } 57 return self; 58 } 59 60 - (void)dealloc { 61 if ([[self menu] delegate] == self) 62 [[self menu] setDelegate:nil]; 63 [super dealloc]; 64 } 65 66 - (NSMenu*)menu { 67 return menu_; 68 } 69 70 - (BOOL)validateMenuItem:(NSMenuItem*)menuItem { 71 AppController* controller = [NSApp delegate]; 72 return ![controller keyWindowIsModal]; 73 } 74 75 // NSMenu delegate method: called just before menu is displayed. 76 - (void)menuNeedsUpdate:(NSMenu*)menu { 77 bridge_->UpdateMenu(menu); 78 } 79 80 // Return the a BookmarkNode that has the given id (called 81 // "identifier" here to avoid conflict with objc's concept of "id"). 82 - (const BookmarkNode*)nodeForIdentifier:(int)identifier { 83 return GetBookmarkNodeByID(bridge_->GetBookmarkModel(), identifier); 84 } 85 86 // Open the URL of the given BookmarkNode in the current tab. 87 - (void)openURLForNode:(const BookmarkNode*)node { 88 Browser* browser = 89 chrome::FindTabbedBrowser(bridge_->GetProfile(), 90 true, 91 chrome::HOST_DESKTOP_TYPE_NATIVE); 92 if (!browser) { 93 browser = new Browser(Browser::CreateParams( 94 bridge_->GetProfile(), chrome::HOST_DESKTOP_TYPE_NATIVE)); 95 } 96 WindowOpenDisposition disposition = 97 ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); 98 OpenURLParams params( 99 node->url(), Referrer(), disposition, 100 content::PAGE_TRANSITION_AUTO_BOOKMARK, false); 101 browser->OpenURL(params); 102 } 103 104 // Open sites under BookmarkNode with the specified disposition. 105 - (void)openAll:(NSInteger)tag 106 withDisposition:(WindowOpenDisposition)disposition { 107 int identifier = tag; 108 109 const BookmarkNode* node = [self nodeForIdentifier:identifier]; 110 DCHECK(node); 111 112 Browser* browser = 113 chrome::FindTabbedBrowser(bridge_->GetProfile(), 114 true, 115 chrome::HOST_DESKTOP_TYPE_NATIVE); 116 if (!browser) { 117 browser = new Browser(Browser::CreateParams( 118 bridge_->GetProfile(), chrome::HOST_DESKTOP_TYPE_NATIVE)); 119 } 120 DCHECK(browser); 121 122 if (!node || !browser) 123 return; // shouldn't be reached 124 125 chrome::OpenAll(NULL, browser, node, disposition, browser->profile()); 126 127 if (disposition == NEW_FOREGROUND_TAB) { 128 content::RecordAction(UserMetricsAction("OpenAllBookmarks")); 129 } else if (disposition == NEW_WINDOW) { 130 content::RecordAction(UserMetricsAction("OpenAllBookmarksNewWindow")); 131 } else { 132 content::RecordAction( 133 UserMetricsAction("OpenAllBookmarksIncognitoWindow")); 134 } 135 } 136 137 - (IBAction)openBookmarkMenuItem:(id)sender { 138 NSInteger tag = [sender tag]; 139 int identifier = tag; 140 const BookmarkNode* node = [self nodeForIdentifier:identifier]; 141 DCHECK(node); 142 if (!node) 143 return; // shouldn't be reached 144 145 [self openURLForNode:node]; 146 } 147 148 - (IBAction)openAllBookmarks:(id)sender { 149 [self openAll:[sender tag] withDisposition:NEW_FOREGROUND_TAB]; 150 } 151 152 - (IBAction)openAllBookmarksNewWindow:(id)sender { 153 [self openAll:[sender tag] withDisposition:NEW_WINDOW]; 154 } 155 156 - (IBAction)openAllBookmarksIncognitoWindow:(id)sender { 157 [self openAll:[sender tag] withDisposition:OFF_THE_RECORD]; 158 } 159 160 @end // BookmarkMenuCocoaController 161