OK, I tried the suggestion to do the update in windowDidBecomeKey and this 
works nicely with the following (perhaps a little ugly) code:


- (void) specialiseCloseMenu:(BOOL)state {
  NSMenu *mainMenu = [[NSApplication sharedApplication] mainMenu];
  NSMenu *fileMenu = [[mainMenu itemAtIndex:1] submenu];
  NSMenuItem *closeMenuItem = [fileMenu itemWithTag:1090];
  NSMenuItem *closeTabMenuItem = [fileMenu itemWithTag:1110];
  
  if (state) {
    [closeMenuItem setKeyEquivalent:@"W"];
    [closeTabMenuItem setKeyEquivalent:@"w"];
  } else {
    [closeMenuItem setKeyEquivalent:@"w"];
    [closeTabMenuItem setKeyEquivalent:@""];
  }
}

- (void) windowDidBecomeKey:(NSNotification *)notification {
  [self specialiseCloseMenu:YES];
}

- (void) windowDidResignKey:(NSNotification *)notification {
  [self specialiseCloseMenu:NO];
}

Thanks all for your help and thoughts.

Cheers,

Martin

On 20 Oct 2013, at 01:21 pm, Martin Hewitson <martin.hewit...@aei.mpg.de> wrote:

> 
> On 20 Oct 2013, at 01:15 am, Kyle Sluder <k...@ksluder.com> 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 <ag...@mac.com> 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 <martin.hewit...@aei.mpg.de> 
>>>> 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 <martin.hewit...@aei.mpg.de> 
>>>>> 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 
>>>>>> <witness.of.teacht...@gmx.net> wrote:
>>>>>> 
>>>>>> 
>>>>>>> On 19 Oct 2013, at 14:27, Andy Lee <ag...@mac.com> wrote:
>>>>>>>> On Oct 19, 2013, at 6:58 AM, Martin Hewitson 
>>>>>>>> <martin.hewit...@aei.mpg.de> 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 (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to