Re: Setting key equivalent for menus depending on window
Re: Setting key equivalent for menus depending on window
- Subject: Re: Setting key equivalent for menus depending on window
- From: Martin Hewitson <email@hidden>
- Date: Sun, 20 Oct 2013 13:21:27 +0200
On 20 Oct 2013, at 01:15 am, Kyle Sluder <email@hidden> wrote:
> Rather than rely on intercepting responder chain-based validation, wouldn't it be much easier and more reliable to make some object the delegate of all of your NSMenus and implement -menuNeedsUpdate:?
>
But wouldn’t this object then need to know details about the different windows which are presented in the app in order to decide which shortcut key to set? I have the feeling that the tabbed window (or its delegate) is the place to make changes to the default menu configuration. I think I will try updating the menu in the windowDidBecomeKey/windowDidResignKey calls of the window’s delegate. The thing I don’t like about this is that the delegate (my document subclass) now needs to have a link to the menu items which are created in the main menu nib. I could try ’scanning' for the relevant menu items, maybe searching by tag. Let’s see how far I get with that.
Thanks!
Martin
> --Kyle Sluder
>
>> On Oct 19, 2013, at 1:28 PM, Andy Lee <email@hidden> wrote:
>>
>> Uli and I both remembered the app delegate is checked *after* the window-related objects in the responder chain, which is what you discovered.
>>
>> I *thought* you could work around this by changing the actions of the Close menu items to methods that only the app delegate implements. But you really don't want to do that, because it'll break any parts of the built-in menu validation that assume performClose: is the action for closing windows.
>>
>> So I propose yet another solution, which may well be, again, flawed. It does not go through validateMenuItem:. The following may seem like a lot of explaining, but it is only a few one- or two-line methods.
>>
>> * Have the app delegate listen for NSWindowDidBecomeMainNotification.
>> * Handle the notification by setting the menu item shortcuts appropriately for the main window.
>>
>> There are different approaches you could take to set the shortcuts appropriately for the window. One way would be to add two category methods on NSWindow, something like
>>
>> + (void)updateShortcutForCloseMenuItem:(NSMenuItem *)menuItem
>> {
>> [menuItem setKeyEquivalent:@"w"];
>> }
>>
>> + (void)updateShortcutForCloseTabMenuItem:(NSMenuItem *)menuItem
>> {
>> [menuItem setKeyEquivalent:@""];
>> }
>>
>> For your window that has tabs, use an NSWindow subclass that overrides these methods:
>>
>> + (void)updateShortcutForCloseMenuItem:(NSMenuItem *)menuItem
>> {
>> [menuItem setKeyEquivalent:@"W"];
>> }
>>
>> + (void)updateShortcutForCloseTabMenuItem:(NSMenuItem *)menuItem
>> {
>> [menuItem setKeyEquivalent:@"w"];
>> }
>>
>> Your app delegate could have outlets to the two menu items in question. Then your notification-handling method can be:
>>
>> - (void)handleWindowDidBecomeMainNotification:(NSNotification *)notif
>> {
>> [[[NSApp mainWindow] class] updateShortcutForCloseMenuItem:_closeMenuItem];
>> [[[NSApp mainWindow] class] updateShortcutForCloseTabMenuItem:_closeTabMenuItem];
>> }
>>
>> I think the only case this does not handle is when the very last window is closed. You may or may not care what the shortcuts are, since the menu items will be dimmed. If you do care, you can:
>>
>> * Have the app delegate listen for NSWindowDidResignMainNotification.
>> * Handle the notification by first checking whether [NSApp mainWindow] is nil. If so (and *only* if so, for the reason Uli pointed out), set the shortcuts to whatever you want them to be in that case. For example, you could do this (which is why I made those "update" methods class methods):
>>
>> - (void)handleWindowDidResignMainNotification:(NSNotification *)notif
>> {
>> if ([NSApp mainWindow] == nil)
>> {
>> [NSWindow updateShortcutForCloseMenuItem:_closeMenuItem];
>> [NSWindow updateShortcutForCloseTabMenuItem:_closeTabMenuItem];
>> }
>> }
>>
>> --Andy
>>
>>
>>> On Oct 19, 2013, at 2:32 PM, Martin Hewitson <email@hidden> wrote:
>>>
>>> I guess I didn’t understand correctly since my app delegate does not get asked to validate the Close menu item. So far the only thing that get’s asked to validate this is the tabbed window object. Even the window’s delegate is not asked.
>>>
>>> The documentation states:
>>>
>>> For document-based applications, the default responder chain for the main window consists of the following responders and delegates:
>>> • The main window’s first responder and the successive responder objects up the view hierarchy
>>> • The main window itself
>>> • The window's NSWindowController object (which inherits from NSResponder)
>>> • The main window’s delegate.
>>> • The NSDocument object (if different from the main window’s delegate)
>>> • The application object, NSApp
>>> • The application object's delegate
>>> • The application's document controller (an NSDocumentController object, which does not inherit from NSResponder)
>>>
>>> My NSPersistentDocument subclass is the main window’s delegate.
>>>
>>> Clearly my thinking is flawed, but where? If I want the Close menu item to vary depending on the window that is key, and I have to do this with validateMenuItem:, then the responder chain above seems to suggest that I need to have a validateMenuItem: in each and every window in the app. I hope that’s not the case….
>>>
>>> Martin
>>>
>>>
>>>> On 19 Oct 2013, at 07:28 pm, Martin Hewitson <email@hidden> wrote:
>>>>
>>>> OK, so the idea is,
>>>>
>>>> + validateMenuItem in app delegate gets a first shot at setting the keyboard shortcuts
>>>> + I override validateMenuItem in my tabbed window and reset the keyboard shortcuts
>>>> + Other windows stick with the settings arranged by the app delegate
>>>>
>>>> Did I understand correctly?
>>>>
>>>> Thanks to all who replied.
>>>>
>>>> Cheers,
>>>>
>>>> Martin
>>>>
>>>>
>>>>> On 19, Oct, 2013, at 02:46 pm, Uli Kusterer <email@hidden> wrote:
>>>>>
>>>>>
>>>>>> On 19 Oct 2013, at 14:27, Andy Lee <email@hidden> wrote:
>>>>>>> On Oct 19, 2013, at 6:58 AM, Martin Hewitson <email@hidden> wrote:
>>>>>>> Main Window with tabs:
>>>>>>> close (cmd-shift-w)
>>>>>>> close tab (cmd-w)
>>>>>>>
>>>>>>> All other windows:
>>>>>>> close (cmd-w)
>>>>>>> close tab (inactive, no keyboard shortcut)
>>>>>>>
>>>>>>> This is pretty much the way things work in Xcode.
>>>>>>>
>>>>>>> So, my question is, is there a smart way to do this, or do I need to implement -validateMenuItem: on every window in the app and set the keyboard shortcuts there?
>>>>>>
>>>>>> Untested idea: implement windowDidBecomeKey: and windowDidResignKey: in the delegate of the window that has tabs and do the switching of shortcuts there.
>>>>>
>>>>> Would rather recommend against this. I don’t think there’s any guarantee given what gets called first, validateMenuItem: or windowDidResignKey:. You might be obliterating something already set by the incoming window.
>>>>>
>>>>>> If you want to be extra careful you could have two ivars that remember what the shortcuts were before you changed them to cmd-shift-w and cmd-w. Then in windowDidResignKey: plug those shortcuts in rather than hard-code cmd-w and @“”.
>>>>>
>>>>> Also, while I’m not aware of any localization that doesn’t use Cmd-W for close, it’s in general a good idea to keep your shortcuts localizable (e.g. on a German keyboard, there’s no way to type Cmd-~, because it has no ~-key, so window rotation is done using Cmd-< there).
>>>>>
>>>>> I’d recommend adding a validateMenuItem: handler in the application delegate, as long as you’re aware that this won’t be called for modal panels or windows that have sheets on them, but since those generally don’t enable the “Close” menu item, you should be fine. At least then you’re modifying the items.
>>>>>
>>>>> Also, I’m not sure whether menu shortcut disambiguation lets you do that, but have you tried hiding and showing menu items with the same names but different shortcuts instead of actually changing the items’ shortcut? I.e. create your menu as
>>>>>
>>>>> Close Cmd-Shift-W -> -performCloseForTabbedWindow:
>>>>> Close Cmd-W -> -performClose:
>>>>> Close Tab Cmd-W -> -performCloseTab:
>>>>> Close Tab -> -performCloseTabDummy:
>>>>>
>>>>> And then hide/show the “tab” items? That way, localization would be easier, and you’re not hard-coding any shortcuts. Though that doesn’t solve the issue of properly restoring the items after you’ve hidden them.
>>>>>
>>>>> Cheers,
>>>>> -- Uli Kusterer
>>>>> “The Witnesses of TeachText are everywhere...”
>>>>> http://zathras.de
>>>>
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden