Chromium Code Reviews| Index: chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm |
| diff --git a/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm b/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm |
| index 6d3cd88777924595c3554a6767da7a36d40e2e66..12c96bbf3b8f6bd60e86ba2dded7f8c72a251da1 100644 |
| --- a/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm |
| +++ b/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm |
| @@ -5,11 +5,20 @@ |
| #import "chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.h" |
| #include "base/logging.h" |
| +#import "base/mac/foundation_util.h" |
| +#include "chrome/app/chrome_command_ids.h" |
| +#import "chrome/browser/app_controller_mac.h" |
| +#include "chrome/browser/fullscreen.h" |
| #include "chrome/browser/global_keyboard_shortcuts_mac.h" |
| +#include "chrome/browser/profiles/profile.h" |
| +#include "chrome/browser/ui/bookmarks/bookmark_utils.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| +#include "chrome/browser/ui/browser_window.h" |
| #import "chrome/browser/ui/cocoa/browser_window_controller_private.h" |
| -#import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" |
| +#include "chrome/browser/ui/toolbar/encoding_menu_controller.h" |
| +#include "content/public/browser/web_contents.h" |
| +#import "ui/base/cocoa/cocoa_base_utils.h" |
| namespace { |
| @@ -61,6 +70,50 @@ bool HandleExtraBrowserKeyboardShortcut(NSEvent* event, NSWindow* window) { |
| CommandForBrowserKeyboardShortcut); |
| } |
| +// Update a toggle state for an item if modified. The item may be an NSMenuItem |
| +// or NSButton. Called by -validateUserInterfaceItem:. |
| +void UpdateToggleStateWithTag(NSInteger tag, id item, NSWindow* window) { |
| + if (![item respondsToSelector:@selector(state)] || |
| + ![item respondsToSelector:@selector(setState:)]) |
| + return; |
| + |
| + Browser* browser = chrome::FindBrowserWithWindow(window); |
| + DCHECK(browser); |
| + |
| + // On Windows this logic happens in bookmark_bar_view.cc. This simply updates |
| + // the menu item; it does not display the bookmark bar itself. |
| + if (tag == IDC_SHOW_BOOKMARK_BAR) { |
| + bool toggled = browser->window()->IsBookmarkBarVisible(); |
| + NSInteger oldState = [item state]; |
| + NSInteger newState = toggled ? NSOnState : NSOffState; |
| + if (oldState != newState) |
| + [item setState:newState]; |
| + return; |
| + } |
| + |
| + // Update the checked/unchecked state of items in the encoding menu. |
| + // On Windows, this logic is part of |EncodingMenuModel| in |
| + // browser/ui/views/toolbar_view.h. |
| + EncodingMenuController encoding_controller; |
| + if (!encoding_controller.DoesCommandBelongToEncodingMenu(tag)) |
| + return; |
| + |
| + Profile* profile = browser->profile(); |
| + DCHECK(profile); |
| + content::WebContents* current_tab = |
| + browser->tab_strip_model()->GetActiveWebContents(); |
| + if (!current_tab) |
| + return; |
| + |
| + const std::string encoding = current_tab->GetEncoding(); |
| + |
| + bool toggled = encoding_controller.IsItemChecked(profile, encoding, tag); |
| + NSInteger oldState = [item state]; |
| + NSInteger newState = toggled ? NSOnState : NSOffState; |
| + if (oldState != newState) |
| + [item setState:newState]; |
| +} |
| + |
| } // namespace |
| @implementation ChromeCommandDispatcherDelegate |
| @@ -106,4 +159,159 @@ bool HandleExtraBrowserKeyboardShortcut(NSEvent* event, NSWindow* window) { |
| return HandleDelayedWindowKeyboardShortcut(event, window); |
| } |
| +- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item |
| + window:(NSWindow*)window { |
| + SEL action = [item action]; |
| + if (action != @selector(commandDispatch:) && |
| + action != @selector(commandDispatchUsingKeyModifiers:)) { |
| + // By default, interface items are enabled if the object in the responder |
| + // chain that implements the action does not implement |
| + // -validateUserInterfaceItem. Since we only care about -commandDispatch, |
| + // return YES for all other actions |
| + return YES; |
| + } |
| + |
| + Browser* browser = chrome::FindBrowserWithWindow(window); |
| + DCHECK(browser); |
| + NSInteger tag = [item tag]; |
| + if (!chrome::SupportsCommand(browser, tag)) |
| + return NO; |
| + |
| + // Generate return value (enabled state). |
| + BOOL enable = chrome::IsCommandEnabled(browser, tag); |
| + switch (tag) { |
| + case IDC_CLOSE_TAB: |
| + // Disable "close tab" if the receiving window is not tabbed. |
| + // We simply check whether the item has a keyboard shortcut set here; |
| + // app_controller_mac.mm actually determines whether the item should |
| + // be enabled. |
| + if (NSMenuItem* menuItem = base::mac::ObjCCast<NSMenuItem>(item)) |
| + enable &= !![[menuItem keyEquivalent] length]; |
| + break; |
| + case IDC_FULLSCREEN: { |
| + if (NSMenuItem* menuItem = base::mac::ObjCCast<NSMenuItem>(item)) { |
| + BrowserWindowController* controller = [window windowController]; |
| + if (chrome::mac::SupportsSystemFullscreen()) { |
| + [menuItem setTitle:[controller titleForFullscreenMenuItem]]; |
|
tapted
2015/09/03 04:15:38
titleForFullscreenMenuItem is only used by this fu
jackhou1
2015/09/03 06:15:39
Done.
The logic for what text to show is currentl
|
| + } else { |
| + [menuItem setHidden:YES]; |
| + } |
| + } |
| + break; |
| + } |
| + case IDC_PRESENTATION_MODE: { |
| + if (NSMenuItem* menuItem = base::mac::ObjCCast<NSMenuItem>(item)) { |
| + BrowserWindowController* controller = [window windowController]; |
| + [menuItem setTitle:[controller titleForFullscreenMenuItem]]; |
| + |
| + if (chrome::mac::SupportsSystemFullscreen()) |
| + [menuItem setAlternate:YES]; |
| + } |
| + break; |
| + } |
| + case IDC_SHOW_SIGNIN: { |
| + Profile* original_profile = browser->profile()->GetOriginalProfile(); |
| + [AppController updateSigninItem:item |
| + shouldShow:enable |
| + currentProfile:original_profile]; |
| + break; |
| + } |
| + case IDC_BOOKMARK_PAGE: { |
| + // Extensions have the ability to hide the bookmark page menu item. |
| + // This only affects the bookmark page menu item under the main menu. |
| + // The bookmark page menu item under the wrench menu has its |
| + // visibility controlled by WrenchMenuModel. |
| + bool shouldHide = |
| + chrome::ShouldRemoveBookmarkThisPageUI(browser->profile()); |
| + NSMenuItem* menuItem = base::mac::ObjCCast<NSMenuItem>(item); |
| + [menuItem setHidden:shouldHide]; |
| + break; |
| + } |
| + case IDC_BOOKMARK_ALL_TABS: { |
| + // Extensions have the ability to hide the bookmark all tabs menu |
| + // item. This only affects the bookmark page menu item under the main |
| + // menu. The bookmark page menu item under the wrench menu has its |
| + // visibility controlled by WrenchMenuModel. |
| + bool shouldHide = |
| + chrome::ShouldRemoveBookmarkOpenPagesUI(browser->profile()); |
| + NSMenuItem* menuItem = base::mac::ObjCCast<NSMenuItem>(item); |
| + [menuItem setHidden:shouldHide]; |
| + break; |
| + } |
| + default: |
| + // Special handling for the contents of the Text Encoding submenu. On |
| + // Mac OS, instead of enabling/disabling the top-level menu item, we |
| + // enable/disable the submenu's contents (per Apple's HIG). |
| + EncodingMenuController encoding_controller; |
| + if (encoding_controller.DoesCommandBelongToEncodingMenu(tag)) { |
| + enable &= |
| + chrome::IsCommandEnabled(browser, IDC_ENCODING_MENU) ? YES : NO; |
|
tapted
2015/09/03 04:15:38
nit: I don't think the YES : NO is necessary. It's
jackhou1
2015/09/03 06:15:39
Done.
|
| + } |
| + } |
| + |
| + // If the item is toggleable, find its toggle state and |
| + // try to update it. This is a little awkward, but the alternative is |
| + // to check after a commandDispatch, which seems worse. |
| + UpdateToggleStateWithTag(tag, item, window); |
| + |
| + return enable; |
| +} |
| + |
| +- (void)commandDispatch:(id)sender window:(NSWindow*)window { |
| + DCHECK(sender); |
| + // Identify the actual BWC to which the command should be dispatched. It might |
|
tapted
2015/09/03 04:15:38
nit: BWC -> Browser?
jackhou1
2015/09/03 06:15:39
Done.
|
| + // belong to a background window, yet this controller gets it because it is |
|
tapted
2015/09/03 04:15:38
controller -> dispatcher? (or something?)
jackhou1
2015/09/03 06:15:39
Done.
|
| + // the foreground window's controller and thus in the responder chain. Some |
| + // senders don't have this problem (for example, menus only operate on the |
| + // foreground window), so this is only an issue for senders that are part of |
| + // windows. |
| + NSWindow* targetWindow = window; |
| + if ([sender respondsToSelector:@selector(window)]) |
| + targetWindow = [sender window]; |
| + Browser* browser = chrome::FindBrowserWithWindow(targetWindow); |
| + DCHECK(browser); |
| + |
| + // When system fullscreen is available, it supercedes presentation mode. |
| + int tag = [sender tag]; |
| + if (tag == IDC_PRESENTATION_MODE && chrome::mac::SupportsSystemFullscreen()) |
| + tag = IDC_FULLSCREEN; |
| + |
| + chrome::ExecuteCommand(browser, tag); |
| +} |
| + |
| +- (void)commandDispatchUsingKeyModifiers:(id)sender window:(NSWindow*)window { |
| + DCHECK(sender); |
| + |
| + if (![sender isEnabled]) { |
| + // This code is reachable e.g. if the user mashes the back button, queuing |
| + // up a bunch of events before the button's enabled state is updated: |
| + // http://crbug.com/63254 |
| + return; |
| + } |
| + |
| + // See comment above for why we do this. |
|
tapted
2015/09/03 04:15:38
Perhaps a FindBrowserForSender() function in an an
jackhou1
2015/09/03 06:15:39
Done.
|
| + NSWindow* targetWindow = window; |
| + if ([sender respondsToSelector:@selector(window)]) |
| + targetWindow = [sender window]; |
| + Browser* browser = chrome::FindBrowserWithWindow(targetWindow); |
| + DCHECK(browser); |
| + |
| + NSInteger command = [sender tag]; |
| + NSUInteger modifierFlags = [[NSApp currentEvent] modifierFlags]; |
| + if ((command == IDC_RELOAD) && |
| + (modifierFlags & (NSShiftKeyMask | NSControlKeyMask))) { |
| + command = IDC_RELOAD_IGNORING_CACHE; |
| + // Mask off Shift and Control so they don't affect the disposition below. |
| + modifierFlags &= ~(NSShiftKeyMask | NSControlKeyMask); |
| + } |
| + if (![[sender window] isMainWindow]) { |
| + // Remove the command key from the flags, it means "keep the window in |
| + // the background" in this case. |
| + modifierFlags &= ~NSCommandKeyMask; |
| + } |
| + chrome::ExecuteCommandWithDisposition( |
| + browser, command, ui::WindowOpenDispositionFromNSEventWithFlags( |
| + [NSApp currentEvent], modifierFlags)); |
| +} |
| + |
| @end // ChromeCommandDispatchDelegate |