Certain key equivalents cannot be used for NSMenuItem - cocoa

I have an NSMenuItem for which I would like to use the key equivalent Command-Option-C. However, when I set the key equivalent in IB, it does not get associated with the menu item when the app is actually run. The entry has no visible key equivalent, and that command does not invoke the item. Other key equivalents, like Shift-Control-C, do indeed work. The one I am trying to use does not conflict with any other key equivalent in the app.
What could be causing this seemingly random problem?

Command-Option-C works just fine here. Could it be that you have a custom keyboard shortcut set up in the keyboard system preferences that uses the same key combination? That would override the application's own shortcuts.

Is it possible the menu item in question is a "special" menu item which may be getting substituted at launch-time by the system? If so, it would be helpful to know whether you are able to set the same keyboard shortcut on a different, perhaps less interesting menu item.
I don't really have an authoritative understanding of which menu items may get this kind of treatment, but have a suspicion for example that maybe the "Help" menu, "Application" menu, or others that are common across many apps get tweaked or even regenerated dynamically, altering what you specified in the nib.
The easiest workaround I would shoot for first is to call setKeyEquvialent: directly on the menu time from code, after the nib has loaded. I couldn't tell from your Twitter summary if you had already tried this, and it also failed.

Check the tag on your menu item. If set to certain values it might Cocoa to override stuff
Check your system Prefs aren't overriding key bindings
Check the key binding doesn't already exist elsewhere in the menu hierarchy, especially in the edit menu

Related

Make "Close All" (cmd+option+W) apply only to one type of document windows

I have an application that manages different types of NSDocument subclasses (along with matching NSWindow subclasses).
For instance, it's possible that the app has one window of type A open, and two windows of type B.
Now, if a window of type B is active, and the user chooses "Close All" or hits cmd+option+W, all my app's windows are sent the close message.
But I only want all of the active window type's windows closed instead, i.e. only the two type B, not the type A window. How do I accomplish this?
I currently have no explicit menu entry for "Close All". Instead, macOS provides that automagically. If there perhaps a way to intercept a "closeAll" message? Can't find one, though.
AppKit will add the Close All menu item if there isn't one. Add an alternate menu item item with key equivalent cmd+option+W below the Close menu and connect it to your own action method.
You might succeed with overriding your document's canClose(withDelegate:,shouldClose:,contextInfo:) to return whether a document should be closed.
If this doesn't behave the way you want, you can create a subclass of NSDocumentController (if you don't have one already). Details on how to do that vary, but usually you have main (menu) XIB or main Storyboard, which has a "Document Controller" object: set its class to your custom class.
Then override closeAllDocuments(withDelegate:,didCloseAllSelector:,contextInfo:) and implement your custom logic.
Note that you should detect whether your app is about to quit and then really do close all you documents (unless you really want to prevent the app quit, e.g. because a document is dirty).
After some digging I figured out where the auto-generated "Close All" menu item sends its action to: To the closeAll: selector of the application target:
Thus my solution is to subclass NSApplication and implement the handler there, which then simply closes all windows that are of the same type (this assumes that I use specific subclasses for my different types of windows):
- (IBAction)closeAll:(id)sender {
Class windowClass = self.keyWindow.class;
for (NSWindow *w in self.windows) {
if (windowClass == w.class) {
[w performClose:sender];
}
}
}
Caution: If you adopt this pattern be aware that:
The closeAll: selector is not documented nor mentioned in the header files, meaning that Apple might feel free to change in a future SDK, though I find that unlikely. It will probably not break anything if that happens, but instead your custom handler won't be called any more.
The code simply tells all windows to close, ignoring the fact that one might reject to be closed, e.g. by user interaction. In that case you may want to stop the loop instead of continuing to close more windows (though I know of no easy way to accomplish that).

Drop down window to edit Cocoa pop-up menu items

I'm relatively new to Cocoa and I would like to implement the ability to add or delete items from a pop-up menu in the same way that the OS X System Preferences/Network Location pop-up works. Selecting the 'Edit Locations...' option rolls down a window that provides the ability to add to, or delete from the existing Location list. My interest in doing things this way is as much about conforming to the relevant Human Interface Guidelines as having a way to dynamically change the menu content. (I have no real problem with the 'background' coding side of things, it's the user interface that's my primary issue at this stage.)
Is this a standard IB View?
On the surface, I can't see anything appropriate, but maybe that's just my inexperience. I'm assuming that, because this is not an uncommon sort of requirement, the task should be pretty straightforward and that Apple, or someone, would even have a relevant code sample to show how to define such a window.
Can anyone point me in the right direction?
Sorry for the late answer. I found this tutorial: http://cocoadevcentral.com/articles/000014.php

How to maintain focus on menu after clicking a menu command

Simple version
Is there any way to maintain focus on menu after clicking a menu command?
Detailed version
Specifically, I've made a menu with some menu item with checked property. The problem is that each time I click checked menu item the menu lose its focus. It can be pretty annoying when there is a number of menu item with checked property and I want to manipulate them at once.
The most elegant solution for the problem would be maintaining focus on menu, but I can't find a way to apply it. Is it possible? And if so, what's the way to do that?
Even if there would a solution for it, sooner or later you will enter a situation in which a numerical or string property is changed via the menu, and then it becomes even impossible to keep the focus on the menu (while the dialog requesting the number or string is on the screen).
The first, simple alternative would be to put the checkable menu items on a toolbar or ribbon (just like Word does with Bold, Italic, Underline, ...). Numerical/string properties can then also be added on the toolbar or ribbon.
A second alternative could be to have a more complete configuration dialog in which the user can change all the configuration items. The configuration dialog can co-exist with the current checkable items, so users simply changing one check and users changing many properties all get a quick way of doing what they want.
You might also pose this question on https://ux.stackexchange.com/ (this sibling site is more oriented towards good user interface practices).

Trouble with data not saving with bindings and shared NSUserDefaults in IB

I'm having a bit of a strange issue that I can't quite figure out. I'm somewhat of a n00b to Interface Builder. What I am trying to do seems like it should be simple, but it's not working for some reason.
In interface builder I have a preferences window with a simple NSTextField. I have set the value binding to the Shared User Defaults Controller with the controller key "values" and model key "test". I build/run my app and open the preferences window, type some random value into said text field, close the window. Command-Q the app. Then in a shell i do a "defaults read com.xxx.yyy" for my app and the key and value are nowhere to be found. That being said, it seems like the next time I fire up the app and change the value it works but only if I switch focus off of the NSTextField before closing the window.
In the documentation for NSUserDefaults it says that the shared controller saves values immediately, am I missing something stupid here?
Thanks for any help.
I'm answering this a long time after it was asked in case others find it useful.
It sounds like you need to set "Continuously Updates Values" for the text field you've bound. Otherwise, the value is only sent and, accordingly, the preferences only updated when something happens to 'finalise' the edit. That's usually triggered by pressing Return and probably also happens when you switch focus away from the window (though I just tested this in one of my own applications and it didn't seem to commit the edit).

Disabling/enabling an application menu item

In trying to learn the very fundamentals of menu handling. My test app's menubar has 3 menus -- namely "TestApp", "File" and "Help". I find I can remove these menus entirely, simply by calling say:
NSMenu* rootMenu = [NSApp mainMenu];
[rootMenu removeItemAtIndex:2];
However, I'd only ever want to temporarily disable them (gray them out). Is there an equally simple way to do this, please?
I may be misunderstanding your question, but it seems like you want to be able to gray-out the actual titles of menus that appear with the system's menu bar (Such as graying-out the "File" menu). I'm not sure if it's even possible, but it certainly goes against the Apple Human Interface Guidelines:
A menu’s title is displayed undimmed
even if all of the menu’s commands are
unavailable (dimmed) at the same time.
Users should always be able to view a
menu’s contents, whether or not they
are currently available.
So, the real solution to the problem is to be able to gray-out all of the menu items within a certain menu when your application is in a certain state. To do this, implement the NSUserInterfaceValidations protocol. It only requires implementing the - (BOOL)validateUserInterfaceItem: method. Typically, when implementing this method, you simply check the selector of the user interface item being validated, and return YES if it should be enabled, or NO if it should not (which will gray-out the menu item).

Resources