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

Side by Side Diff: chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm

Issue 1250403002: [Mac] Move UI item validation to UserInterfaceItemCommandHandler. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@commandexecute
Patch Set: Address comments. Created 5 years, 3 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/chrome_command_dispatcher_delegate.h" 5 #import "chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #import "base/mac/foundation_util.h"
9 #include "chrome/app/chrome_command_ids.h"
10 #import "chrome/browser/app_controller_mac.h"
11 #include "chrome/browser/fullscreen.h"
8 #include "chrome/browser/global_keyboard_shortcuts_mac.h" 12 #include "chrome/browser/global_keyboard_shortcuts_mac.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
9 #include "chrome/browser/ui/browser_commands.h" 15 #include "chrome/browser/ui/browser_commands.h"
10 #include "chrome/browser/ui/browser_finder.h" 16 #include "chrome/browser/ui/browser_finder.h"
17 #include "chrome/browser/ui/browser_window.h"
11 #import "chrome/browser/ui/cocoa/browser_window_controller_private.h" 18 #import "chrome/browser/ui/cocoa/browser_window_controller_private.h"
12 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" 19 #include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
20 #include "content/public/browser/web_contents.h"
21 #import "ui/base/cocoa/cocoa_base_utils.h"
13 22
14 namespace { 23 namespace {
15 24
16 // Type of functions listed in global_keyboard_shortcuts_mac.h. 25 // Type of functions listed in global_keyboard_shortcuts_mac.h.
17 typedef int (*KeyToCommandMapper)(bool, bool, bool, bool, int, unichar); 26 typedef int (*KeyToCommandMapper)(bool, bool, bool, bool, int, unichar);
18 27
19 // If the event is for a Browser window, and the key combination has an 28 // If the event is for a Browser window, and the key combination has an
20 // associated command, execute the command. 29 // associated command, execute the command.
21 bool HandleExtraKeyboardShortcut( 30 bool HandleExtraKeyboardShortcut(
22 NSEvent* event, 31 NSEvent* event,
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 bool HandleDelayedWindowKeyboardShortcut(NSEvent* event, NSWindow* window) { 63 bool HandleDelayedWindowKeyboardShortcut(NSEvent* event, NSWindow* window) {
55 return HandleExtraKeyboardShortcut(event, window, 64 return HandleExtraKeyboardShortcut(event, window,
56 CommandForDelayedWindowKeyboardShortcut); 65 CommandForDelayedWindowKeyboardShortcut);
57 } 66 }
58 67
59 bool HandleExtraBrowserKeyboardShortcut(NSEvent* event, NSWindow* window) { 68 bool HandleExtraBrowserKeyboardShortcut(NSEvent* event, NSWindow* window) {
60 return HandleExtraKeyboardShortcut(event, window, 69 return HandleExtraKeyboardShortcut(event, window,
61 CommandForBrowserKeyboardShortcut); 70 CommandForBrowserKeyboardShortcut);
62 } 71 }
63 72
73 // Update a toggle state for an item if modified. The item may be an NSMenuItem
74 // or NSButton. Called by -validateUserInterfaceItem:.
75 void UpdateToggleStateWithTag(NSInteger tag, id item, NSWindow* window) {
76 if (![item respondsToSelector:@selector(state)] ||
77 ![item respondsToSelector:@selector(setState:)])
78 return;
79
80 Browser* browser = chrome::FindBrowserWithWindow(window);
81 DCHECK(browser);
82
83 // On Windows this logic happens in bookmark_bar_view.cc. This simply updates
84 // the menu item; it does not display the bookmark bar itself.
85 if (tag == IDC_SHOW_BOOKMARK_BAR) {
86 bool toggled = browser->window()->IsBookmarkBarVisible();
87 NSInteger oldState = [item state];
88 NSInteger newState = toggled ? NSOnState : NSOffState;
89 if (oldState != newState)
90 [item setState:newState];
91 return;
92 }
93
94 // Update the checked/unchecked state of items in the encoding menu.
95 // On Windows, this logic is part of |EncodingMenuModel| in
96 // browser/ui/views/toolbar_view.h.
97 EncodingMenuController encoding_controller;
98 if (!encoding_controller.DoesCommandBelongToEncodingMenu(tag))
99 return;
100
101 Profile* profile = browser->profile();
102 DCHECK(profile);
103 content::WebContents* current_tab =
104 browser->tab_strip_model()->GetActiveWebContents();
105 if (!current_tab)
106 return;
107
108 const std::string encoding = current_tab->GetEncoding();
109
110 bool toggled = encoding_controller.IsItemChecked(profile, encoding, tag);
111 NSInteger oldState = [item state];
112 NSInteger newState = toggled ? NSOnState : NSOffState;
113 if (oldState != newState)
114 [item setState:newState];
115 }
116
117 // Get the text for the "Enter/Exit Fullscreen/Presentation Mode" menu item.
118 // TODO(jackhou): Move the logic out of BrowserWindowController.
119 NSString* GetTitleForFullscreenMenuItem(NSWindow* window) {
120 BrowserWindowController* controller = [window windowController];
121 return [controller titleForFullscreenMenuItem];
tapted 2015/09/03 06:54:49 Can you remove titleForFullscreenMenuItem and put
jackhou1 2015/09/03 08:12:29 Ah oops, I see what you mean. Done.
122 }
123
124 // Identify the actual Browser to which the command should be dispatched. It
125 // might belong to a background window, yet this dispatcher gets it because it
tapted 2015/09/03 06:54:49 nit: this -> another ?
jackhou1 2015/09/03 08:12:29 Done.
126 // is the foreground window's dispatcher and thus in the responder chain. Some
127 // senders don't have this problem (for example, menus only operate on the
128 // foreground window), so this is only an issue for senders that are part of
129 // windows.
130 Browser* FindBrowserForSender(id sender, NSWindow* window) {
131 NSWindow* targetWindow = window;
132 if ([sender respondsToSelector:@selector(window)])
133 targetWindow = [sender window];
134 Browser* browser = chrome::FindBrowserWithWindow(targetWindow);
135 DCHECK(browser);
136 return browser;
137 }
138
64 } // namespace 139 } // namespace
65 140
66 @implementation ChromeCommandDispatcherDelegate 141 @implementation ChromeCommandDispatcherDelegate
67 142
68 - (BOOL)handleExtraKeyboardShortcut:(NSEvent*)event window:(NSWindow*)window { 143 - (BOOL)handleExtraKeyboardShortcut:(NSEvent*)event window:(NSWindow*)window {
69 return HandleExtraBrowserKeyboardShortcut(event, window) || 144 return HandleExtraBrowserKeyboardShortcut(event, window) ||
70 HandleExtraWindowKeyboardShortcut(event, window) || 145 HandleExtraWindowKeyboardShortcut(event, window) ||
71 HandleDelayedWindowKeyboardShortcut(event, window); 146 HandleDelayedWindowKeyboardShortcut(event, window);
72 } 147 }
73 148
(...skipping 25 matching lines...) Expand all
99 // if e.g. the Omnibox has focus). 174 // if e.g. the Omnibox has focus).
100 return HandleExtraWindowKeyboardShortcut(event, window); 175 return HandleExtraWindowKeyboardShortcut(event, window);
101 } 176 }
102 177
103 - (BOOL)postPerformKeyEquivalent:(NSEvent*)event window:(NSWindow*)window { 178 - (BOOL)postPerformKeyEquivalent:(NSEvent*)event window:(NSWindow*)window {
104 // Handle per-window shortcuts like Esc after giving everybody else a chance 179 // Handle per-window shortcuts like Esc after giving everybody else a chance
105 // to handle them 180 // to handle them
106 return HandleDelayedWindowKeyboardShortcut(event, window); 181 return HandleDelayedWindowKeyboardShortcut(event, window);
107 } 182 }
108 183
184 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item
185 window:(NSWindow*)window {
186 SEL action = [item action];
187 if (action != @selector(commandDispatch:) &&
188 action != @selector(commandDispatchUsingKeyModifiers:)) {
189 // By default, interface items are enabled if the object in the responder
190 // chain that implements the action does not implement
191 // -validateUserInterfaceItem. Since we only care about -commandDispatch,
192 // return YES for all other actions
193 return YES;
194 }
195
196 Browser* browser = chrome::FindBrowserWithWindow(window);
197 DCHECK(browser);
198 NSInteger tag = [item tag];
199 if (!chrome::SupportsCommand(browser, tag))
200 return NO;
201
202 // Generate return value (enabled state).
203 BOOL enable = chrome::IsCommandEnabled(browser, tag);
204 switch (tag) {
205 case IDC_CLOSE_TAB:
206 // Disable "close tab" if the receiving window is not tabbed.
207 // We simply check whether the item has a keyboard shortcut set here;
208 // app_controller_mac.mm actually determines whether the item should
209 // be enabled.
210 if (NSMenuItem* menuItem = base::mac::ObjCCast<NSMenuItem>(item))
211 enable &= !![[menuItem keyEquivalent] length];
212 break;
213 case IDC_FULLSCREEN: {
214 if (NSMenuItem* menuItem = base::mac::ObjCCast<NSMenuItem>(item)) {
215 if (chrome::mac::SupportsSystemFullscreen())
216 [menuItem setTitle:GetTitleForFullscreenMenuItem(window)];
217 else
218 [menuItem setHidden:YES];
219 }
220 break;
221 }
222 case IDC_PRESENTATION_MODE: {
223 if (NSMenuItem* menuItem = base::mac::ObjCCast<NSMenuItem>(item)) {
224 [menuItem setTitle:GetTitleForFullscreenMenuItem(window)];
225
226 if (chrome::mac::SupportsSystemFullscreen())
tapted 2015/09/03 06:54:49 ... pretty sure this is dead code now. either it d
jackhou1 2015/09/03 08:12:29 When it does support systemFullscreen, the IDC_PRE
227 [menuItem setAlternate:YES];
228 }
229 break;
230 }
231 case IDC_SHOW_SIGNIN: {
232 Profile* original_profile = browser->profile()->GetOriginalProfile();
233 [AppController updateSigninItem:item
234 shouldShow:enable
235 currentProfile:original_profile];
236 break;
237 }
238 case IDC_BOOKMARK_PAGE: {
239 // Extensions have the ability to hide the bookmark page menu item.
240 // This only affects the bookmark page menu item under the main menu.
241 // The bookmark page menu item under the wrench menu has its
242 // visibility controlled by WrenchMenuModel.
243 bool shouldHide =
244 chrome::ShouldRemoveBookmarkThisPageUI(browser->profile());
245 NSMenuItem* menuItem = base::mac::ObjCCast<NSMenuItem>(item);
246 [menuItem setHidden:shouldHide];
247 break;
248 }
249 case IDC_BOOKMARK_ALL_TABS: {
250 // Extensions have the ability to hide the bookmark all tabs menu
251 // item. This only affects the bookmark page menu item under the main
252 // menu. The bookmark page menu item under the wrench menu has its
253 // visibility controlled by WrenchMenuModel.
254 bool shouldHide =
255 chrome::ShouldRemoveBookmarkOpenPagesUI(browser->profile());
256 NSMenuItem* menuItem = base::mac::ObjCCast<NSMenuItem>(item);
257 [menuItem setHidden:shouldHide];
258 break;
259 }
260 default:
261 // Special handling for the contents of the Text Encoding submenu. On
262 // Mac OS, instead of enabling/disabling the top-level menu item, we
263 // enable/disable the submenu's contents (per Apple's HIG).
264 EncodingMenuController encoding_controller;
265 if (encoding_controller.DoesCommandBelongToEncodingMenu(tag))
266 enable &= chrome::IsCommandEnabled(browser, IDC_ENCODING_MENU);
267 }
268
269 // If the item is toggleable, find its toggle state and
270 // try to update it. This is a little awkward, but the alternative is
271 // to check after a commandDispatch, which seems worse.
272 UpdateToggleStateWithTag(tag, item, window);
273
274 return enable;
275 }
276
277 - (void)commandDispatch:(id)sender window:(NSWindow*)window {
278 DCHECK(sender);
279 Browser* browser = FindBrowserForSender(sender, window);
tapted 2015/09/03 06:54:49 nit: These temporaries are probably no longer need
jackhou1 2015/09/03 08:12:29 Done.
280
281 // When system fullscreen is available, it supercedes presentation mode.
282 int command = [sender tag];
283 if (command == IDC_PRESENTATION_MODE &&
284 chrome::mac::SupportsSystemFullscreen())
285 command = IDC_FULLSCREEN;
286
287 chrome::ExecuteCommand(browser, command);
288 }
289
290 - (void)commandDispatchUsingKeyModifiers:(id)sender window:(NSWindow*)window {
291 DCHECK(sender);
292
293 if (![sender isEnabled]) {
294 // This code is reachable e.g. if the user mashes the back button, queuing
295 // up a bunch of events before the button's enabled state is updated:
296 // http://crbug.com/63254
297 return;
298 }
299
300 Browser* browser = FindBrowserForSender(sender, window);
301
302 NSInteger command = [sender tag];
303 NSUInteger modifierFlags = [[NSApp currentEvent] modifierFlags];
304 if ((command == IDC_RELOAD) &&
305 (modifierFlags & (NSShiftKeyMask | NSControlKeyMask))) {
306 command = IDC_RELOAD_IGNORING_CACHE;
307 // Mask off Shift and Control so they don't affect the disposition below.
308 modifierFlags &= ~(NSShiftKeyMask | NSControlKeyMask);
309 }
310 if (![[sender window] isMainWindow]) {
311 // Remove the command key from the flags, it means "keep the window in
312 // the background" in this case.
313 modifierFlags &= ~NSCommandKeyMask;
314 }
315 chrome::ExecuteCommandWithDisposition(
316 browser, command, ui::WindowOpenDispositionFromNSEventWithFlags(
317 [NSApp currentEvent], modifierFlags));
318 }
319
109 @end // ChromeCommandDispatchDelegate 320 @end // ChromeCommandDispatchDelegate
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698